Maximum difference between final and initial sum - java

I am new to programming and having trouble solving one task. I have several input example. First line contains two numbers m (number of digits on paper, 1<m<1000) and h (limit on the number of operations, 1<h<1000). I have the opportunity, no more than h times, to take any number from a piece of paper (means m), then paint over one of the old digits, and write a new arbitrary digit in its place. By what maximum value can I be able to increase the sum of all the numbers on the piece of paper?
First example:
Input:
5 2 //m and h
1 3 1 4 5 //m = 5, so I can add 5 arbitrary numbers and h=2, so I can change 2 numbers
Output:
16 // cause I changed 1 and 1 to 9 and 9, so the difference 8 and 8 and the sum is 16
Second example:
Input:
3 1
99 5 85
Output:
10 //85 to 95, so the difference is 10
Third example:
Input:
1 10
9999
Output:
0 // nothing to be change
What I have for now:
Scanner sc = new Scanner(System.in);
System.out.println("Enter the number: ");
int m = sc.nextInt();
int h = sc.nextInt();
System.out.println("Entered: " + m);
System.out.println("Entered: " + h);
int[] numbers = new int[m];
for(int i = 0; i < m; ++i) {
numbers[i] = sc.nextInt();
}
Arrays.sort(numbers);
//here is my logic: I am changing 1 to 9
for (int i = 0; i < h; i++) {
if (numbers[i] < 10) {
numbers[i] = 9;
}
else if (numbers[i] > 9 and numbers[i] < 100) {
numbers[i] = 99;
}
}
sc.close();
My logic can work for the first example, but for the second example it won't work. Can you assist me if I am using right logic or is there any easier way to solve this? Thanks in advance.

I quickly came up with below solution
public static void calculateMax(int m,int h, int[] arr){
int sum = 0;
ArrayList<Integer> al = new ArrayList<>();
for(int i=0;i<arr.length;i++){
String stringNum = Integer.toString(arr[i]);
int num = Integer.parseInt(stringNum.substring(0, 1));
if(num!=9){
al.add(Integer.parseInt(("9"+stringNum.substring(1)))-arr[i]);
continue;
}
al.add(0);
}
Collections.sort(al);
int j = al.size()-1;
for(int i=0;i<h && j>0;i++){
sum+=al.get(j--);
}
System.out.println(sum);
}
Here what I am doing is basically, calculating for each number what we can get as maximum by removing one digit and replacing by 9. And I am storing them in a list. Then we can sort that list and get 'h' largest numbers from stored list, and essentially getting the sum of them and printing it.

Break each input number into its digits times the appropriate power of 10. Sort these by powers of 10 descending, digits ascending. Apply your operation in this order.
E.g., 876, 12, 42 -> 800, 70, 6, 10, 2, 40, 2 -> 800, 10, 40, 70, 2, 2, 6.

Related

Add the consecutive digits of a birthdate recursively till it reaches to a single digit

I am developing a numerology application which has to provide a result which is similar to the following,
1 5 0 8 1 9 9 4
6 5 8 9 1 1 1
1 1 1 1 2 2
2 2 2 3 4
4 4 5 7
8 9 1
1 1
2
It has to add the consecutive digits and retain the first digit if the sum is of 2 digits.
I am missing something. Adding a while loop for the length of intList doesn't seem to work.
int date;
List<Integer> sumList = new ArrayList<Integer>();
Scanner s = new Scanner(System.in);
System.out.println("Enter the date");
date = s.nextInt();
int len = Integer.toString(date).length();
int[] convertarray = new int[len];
for (int index = 0; index < len; index++) {
convertarray[index] = date % 10;
date /= 10;
}
List<Integer> intList = new ArrayList<Integer>();
for (int i : convertarray) {
intList.add(i);
}
Collections.reverse(intList);
System.out.println(intList);
int sum = 0;
int size = intList.size();
for (int i = 0; i < intList.size() - 1; i++) {
sum = intList.get(i) + intList.get(i + 1);
int length = (int) (Math.log10(sum) + 1);
if (length > 1) {
int firstDigit = Integer.parseInt(Integer.toString(sum).substring(0, 1));
sum = firstDigit;
}
System.out.print(sum + " ");
sumList.add(sum);
}
System.out.println("\n");
intList.clear();
intList = sumList;
My output is something like,
1 5 0 8 1 9 9 4
6 5 8 9 1 1 1
A simple recursive solution:
public static void main(String[] args) throws Exception {
String birthday = "01091995";
int[] digits = Arrays.stream(birthday.split("")).mapToInt(Integer::parseInt).toArray();
recursiveFunction(digits);
}
private static void recursiveFunction(int[] digits) {
if(digits.length == 1) {
// Base Case
System.out.println(digits[0]);
} else {
// Recursive Case
System.out.println(Arrays.toString(digits));
int[] digitsProcessed = new int[digits.length -1];
for (int i = 0; i < digits.length - 1; i++) {
digitsProcessed[i] = digits[i] + digits[i+1]; // Logic
}
recursiveFunction(digitsProcessed);
}
}
This produces:
[0, 1, 0, 9, 1, 9, 9, 5] // 8 numbers
[1, 1, 9, 10, 10, 18, 14] // 7 numbers
[2, 10, 19, 20, 28, 32] // 6 numbers
[12, 29, 39, 48, 60] // 5 numbers
[41, 68, 87, 108] // 4 numbers
[109, 155, 195] // 3 numbers
[264, 350] // 2 numbers
614 // 1 number
Adding a while loop for the length of intList doesn't seem to work.
Well it can be done with loops, but it would be harder and messier.
An algorithm with recursion would be the following:
Init the array of integers.
Call the recursive function "F" with the array.
From now, the recursive function behaviour:
Check if the recieved array's length is 1.
If it is, print the element and terminate.
If it is not:
Print the recieved array.
Make a new array.
Put in this new array the result of processing the recieved one adding as intended.
Call the recursive function "F" with this new array.

How to count all possible cases?

For example I have array with length n=3:
for(int i = 0; i < n; i++) {
array[i] = i;
}
So the cases should be:
1. 0
2. 1
3. 2
4. 0 1
5. 0 2
6. 1 2
7. 0 1 2
So the number of cases should be 7 for n = 3.
In my code:
int n = 3;
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = i;
}
int sum = 0;
for (int i = 0; i < n; i++) {
System.out.println(array[i] + " ");
sum++;
for (int j = i; j < n; j++) {
System.out.print(array[j] + " ");
}
System.out.println();
sum++;
}
System.out.println("sum = " + sum);
Output is:
0
0 1 2
1
1 2
2
2
sum = 6
The number 2 is two times so it is wrong and sum is actually = 5. And I don't get cases
4. 0 1
and
5. 0 2
How to count all possible cases?
Sets, not arrays
The first important observance is that you are not using fixed length arrays here but sets of different lengths.
Take a look at your example. You allow
0
1
2
0, 1
0, 2
1, 2
which are not all of size 3.
Also you don't differentiate between
0, 1
1, 0
so order doesn't matter, like in sets.
Power set
That's why you're actually describing power sets here. For the example set {0, 1, 2} its power set is defined as
P({0, 1, 2}) = {
{}, // empty set
{0},
{1},
{2},
{0, 1},
{0, 2},
{1, 2},
{0, 1, 2}
}
Fortunately there exists an easy closed formula for their size. If n is the size of the input set the size of the power set is
2^n
But they also count the empty set, so you will need to -1 if you don't want that:
2^n - 1
Solution
Thus in Java you could write
int Set<Integer> input = ...
int size = (int) Math.pow(2, input.size()) - 1;
and that's all, you don't need to build the contents manually.
But if you're curious and want to build them, take a look at questions like Obtaining a powerset of a set in Java. It's an implementation of the recursive formula shown at Wikipedia.
So, totally inefficient but also working:
int Set<Integer> input = ...
// Build the power-set using the method from linked question
Set<Set<Integer>> power = powerSet(input);
int size = power.size() - 1;

USACO(JAVA) : Algorithms Complete Search

So here is the link to problem statement : http://train.usaco.org/usacoprob2?a=ZSMwtXwq7ro&S=comboProblem Statement.
EDIT 1: So the problem is this :
There is a lock and there are 2 valid 3 digit combinations for the lock. One which is set by the user and other one is the master key set by the manufacturer. Also the lock has certain tolerance for errors, ie it will open even if the numbers on the dials are each within at most 2 positions of a valid combination.
For example , suppose user set key was 1, 2, 3 and the master key (manufacturer set) was 4, 5, 6. For these 2 keys 1, 3, 5 is a valid key since the difference between each digit(at same position) of this key and user set key is atmost 2 . But 1, 5, 6 is an invalid combo because the difference between digits of this key and user set key > 2 and same for master key.
Basically what I am doing is pretty naive, I am generating all possible lock combinations and checking for validity of each combination. Here is my code
import java.util.*;
public class combo {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int N = myScanner.nextInt();
int[] keys = new int[3];
int[] masterKeys = new int[3];
for(int i = 0; i < 3; i++){
keys[i] = myScanner.nextInt();
}
for(int i = 0; i < 3; i++){
masterKeys[i] = myScanner.nextInt();
}
int cnt = 0;
int[] combo = new int[3];
for(int i = 1; i <= N; i++){
combo[0] = i;
for(int j = 1; j <= N; j++){
combo[1] = j;
for(int k = 1; k <=N; k++){
combo[2] = k;
if(validCombo(combo, keys, masterKeys)){
cnt += 1;
}
}
}
}
System.out.println(cnt);
}
// bug here
/*
Valid
combo : 1, 3, 5
key : 1, 2, 3
master 4, 5, 6
Invalid
1 5 6
*/
public static boolean validCombo(int[] combo, int[] keys, int[] masterKeys){
boolean checkKeys = true;
boolean checkMasterKeys = true;
for(int i = 0; i < 3; i++){
if(Math.abs((int)(combo[i]-keys[i])) > 2){
checkKeys = false;
}
if(Math.abs((int)(combo[i]-masterKeys[i])) > 2){
checkMasterKeys = false;
}
}
return checkKeys | checkMasterKeys;
}
}
So for inputs N = 50 , keys = 1, 2, 3 and masterKeys = 5, 6,7 , I get output 184 but the correct output is 249 (sample given test case). Can anyone please just give me a hint as to what is wrong with my logic
You aren't taking into account the fact that the numbers wrap around - i.e., when N = 50, then 50 is 1 away from 1, 2 away from 2, etc.
When trying to debug something like this, it might help if you printed out exactly what your program was counting as solutions, and then comparing to the output listed on the problem site, if they give you such details, or just using the extra information to validate your own thought process.
Instead of "trying" all combinations you could compute them
compute the number of overlapping numbers per dial
if distance between the key number and the master key number
is >= 5 --> you have 10 distinct values
is < 5 --> you have (5 - distance) overlapping numbers
examples:
key: 3 master key: 8 distinct numbers: 10 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
key: 3 master key: 6 distinct numbers: 8 = 1, 2, 3, 4, 5, 6, 7, 8
4 and 5 are the overlapping numbers for this dial
if at least for one dial there is no overlapping number then we have the maximum of 250 combinations
if all dials have at least one overlapping number we can compute the
number of overlapping combinations by multiplying the overlapping numbers
of all dials
unique combinations can be computed as max. number - overlapping combinations
example: key: 3, 4, 5 master key: 7, 8, 9
1 2 3 -+
2 3 4 |
3 4 5 |<-- the combinations close to the key
4 5 6 |
5 6 7 -+<-- the only overlapping number
6 7 8 |
7 8 9 |<-- the combinations close to the master key
9 10 11 |
10 11 12 -+
There are 249 valid combinations.
Here a short snippet for the computation.
int numbersPerDail = 50;
int dials = 3;
int[] keys = {2, 2, 3};
int[] masterKeys = {48, 5, 6};
int[] overlappingNumbers = new int[dials];
for (int i = 0; i < dials; i++) {
int distance = Math.max(keys[i], masterKeys[i]) - Math.min(keys[i], masterKeys[i]);
if (distance >= 46) { // the dial is circular
distance = numbersPerDail - distance;
}
overlappingNumbers[i] = 5 - distance;
}
int doubleCombos = 0;
if (overlappingNumbers[0] > 0 && overlappingNumbers[1] > 0 && overlappingNumbers[2] > 0) {
doubleCombos = overlappingNumbers[0] * overlappingNumbers[1] * overlappingNumbers[2];
}
System.out.println("valid combinations = " + (250 - doubleCombos));

Count occurrence of integers in an array

I have an integer array: int[] numbers = new int[...n]; // n being limitless.
Where all the numbers are between 0 and 100.
Say numbers[] was equal to: [52, 67, 32, 43, 32, 21, 12, 5, 0, 3, 2, 0, 0];
I want to count how often each of those numbers occur.
I've got a second array: int[] occurrences = new int[100];.
I'd like to be able to store the amounts like such:
for(int i = 0; i < numbers.length; i++) {
// Store amount of 0's in numbers[] to occurrences[0]
// Store amount of 1's in numbers[] to occurrences[1]
}
So that occurrences[0] would be equal to 3, occurrences[1] would be equal to 0 etc.
Is there any efficient way of doing this without having to resort to external libraries? thanks.
You can simply do something like this:
for (int a : numbers) {
occurrences[a]++;
}
Also, if you mean 0 to 100 inclusive then occurrences will need to be of size 101 (i.e. 100 will need to be the maximum index).
You might also want to perform an "assertion" to ensure that each element of numbers is indeed in the valid range before you update occurrences.
Updated to put results in the 100-array.
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
<P>{#code java IntOccurancesInArray}</P>
**/
public class IntOccurancesInArray {
public static final void main(String[] igno_red) {
int[] ai = new int[]{52, 67, 32, 43, 32, 21, 12, 5, 0, 3, 2, 0, 0};
Map<Integer,Integer> mpNumWHits = new TreeMap<Integer,Integer>();
for(int i = 0; i < ai.length; i++) {
int iValue = ai[i];
if(!mpNumWHits.containsKey(iValue)) {
mpNumWHits.put(iValue, 1);
} else {
mpNumWHits.put(iValue, (mpNumWHits.get(iValue) + 1));
}
}
Set<Integer> stInts = mpNumWHits.keySet();
Iterator<Integer> itrInts = stInts.iterator();
int[] ai100 = new int[100];
int i = 0;
while(itrInts.hasNext()) {
int iValue = itrInts.next();
int iHits = mpNumWHits.get(iValue);
System.out.println(iValue + " found " + iHits + " times");
ai100[iValue] = iHits;
}
for(int j = 0; j < ai100.length; j++) {
if(ai100[j] > 0) {
System.out.println("ai100[" + j + "]=" + ai100[j]);
}
}
}
}
Output:
[C:\java_code\]java IntOccurancesInArray
0 found 3 times
2 found 1 times
3 found 1 times
5 found 1 times
12 found 1 times
21 found 1 times
32 found 2 times
43 found 1 times
52 found 1 times
67 found 1 times
ai100[0]=3
ai100[2]=1
ai100[3]=1
ai100[5]=1
ai100[12]=1
ai100[21]=1
ai100[32]=2
ai100[43]=1
ai100[52]=1
ai100[67]=1
This method is useful for knowing occurrences of all elements
You can reduce the space by finding the length of new array using sorting and taking value of last element + 1
import java.util.Arrays;
public class ArrayMain {
public static void main(String[] args) {
int a[] = {52, 67, 32, 43, 32, 21, 12, 5, 0, 3, 2, 0, 0};
Arrays.sort(a);
int len=a[a.length-1]+1;
int count[]=new int[len];
for(int n:a){
count[n]++;
}
for(int j=0;j<count.length;j++){
if(count[j]>=1){
System.out.println("count:"+j+"---"+count[j]);
}
}
}
}
Time Complexity : O(n)
Space Complexity : O(R) // last element value +1
Note : Creating new array may not be good idea if you have extreme numbers like 1, 2 and 96, 99 etc in terms of space.
For this case sorting and comparing next element is better approach
import java.util.Scanner;
public class CountNumOccurences {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int[] frequency = new int[100];
System.out.println("Enter the first integer: ");
int number = input.nextInt();
//Enter up to 100 integers, 0 to terminate
while (number != 0){
++frequency[number];
//read the next integer
System.out.print(
"Enter the next int value (zero to exit): ");
number = input.nextInt();
}
input.close();
System.out.println("Value\tFrequency");
for (int i = 0; i < frequency.length; i++) {
if (frequency[i] > 0){
if (frequency[i] > 1)
System.out.println(i + " occurs " + frequency[i] + " times");
else
System.out.println(i + " occurs " + frequency[i] + " time");
}
}
}
}

UVA#523 Minimum Transport Cost

UVA link: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=464
I'm lost as to what I'm doing now. I don't know why I'm producing incorrect values. I printed out the array after I looked for shortest path. And it produces this:
[0, 3, 8, 8, 4]
[3, 0, 5, 11, 7]
[8, 5, 0, 9, 12]
[8, 11, 9, 0, 4]
[4, 7, 12, 4, 0]
The sample input is:
1
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
1 3
3 5
2 4
With the sample input, I produce the output:
From 1 to 3 :
Path: 1-->2-->3
Total cost :8
From 3 to 5 :
Path: 3-->2-->5
Total cost :12
From 2 to 4 :
Path: 2-->5-->4
Total cost :11
If I look at my array, it seems to be correct. But the correct answer is:
From 1 to 3 :
Path: 1-->5-->4-->3
Total cost : 21
From 3 to 5 :
Path: 3-->4-->5
Total cost : 16
From 2 to 4 :
Path: 2-->1-->5-->4
Total cost : 17
I think I missed adding the tax, but I don't know where to add it. I tried adding tax[j] to the path[i][j] while doing the shortest path, and then subtracting the tax[x-1] and tax[y-1] (x-1 is my source, y-1 is my destination). It doesn't work, and messes up my path array (it gives value to loops; I don't really need that). I really don't know where to put the tax.
Here is my code for reference:
import java.util.*;
public class Main{
public static final int INF = 9999999;
public static int[][] path;
public static int[][] next;
public static int[] tax;
public static void main(String[] adsf){
Scanner pp = new Scanner(System.in);
int testCases = pp.nextInt();
boolean first = true;
pp.nextLine();
pp.nextLine();
while(testCases-- >0){
String[] s1 = pp.nextLine().split(" ");
int size = s1.length;
path = new int[size][size];
next = new int[size][size];
for(int i = 0; i < path.length; i++)
Arrays.fill(path[i],INF);
tax = new int[size];
for(int j = 0; j < path[0].length; j++){
path[0][j] = Integer.parseInt(s1[j]);
if(path[0][j]==-1)
path[0][j]=INF;
}
for(int i = 1; i < path.length;i++){
s1 = pp.nextLine().split(" ");
for(int j = 0; j < path[0].length; j++){
path[i][j] = Integer.parseInt(s1[j]);
if(path[i][j]==-1)
path[i][j]=INF;
}
}
for(int k=0; k<tax.length;k++){
tax[k] = pp.nextInt();
} pp.nextLine();
apsp();
int x,y;
//for(int i = 0; i < size; i++)
//System.out.println(Arrays.toString(path[i]));
while(pp.hasNextInt()){
if(!first)
System.out.println();
x=pp.nextInt();
y=pp.nextInt();
int cost = path[x-1][y-1];
System.out.println("From "+x+" to "+y+" :");
System.out.print("Path: ");
ArrayList<Integer> print = getpath(x-1,y-1);
for(int l = 0; l < print.size(); l++){
System.out.print(print.get(l)+1);
if(l!=print.size()-1) System.out.print("-->");
else System.out.println();
}
System.out.println("Total cost :"+cost);
first = false;
}
}
}
public static void apsp(){
for(int k=0;k<path.length;k++){
for(int i=0;i<path.length;i++){
for(int j=0;j<path.length;j++){
if (path[i][k] + path[k][j] + tax[j] < path[i][j] + tax[j]) {
path[i][j] = path[i][k]+path[k][j];
next[i][j] = k;
} else{
path[i][j] = path[i][j];
}
}
}
}
}
public static ArrayList<Integer> getpath (int i, int j) {
ArrayList<Integer> pat = getMidPath(i,j);
pat.add(0,i);
pat.add(j);
return pat;
}
public static ArrayList<Integer> getMidPath(int i, int j){
if(next[i][j]==0)
return new ArrayList<Integer>();
ArrayList<Integer> pat = new ArrayList<Integer>();
pat.addAll(getMidPath(i,next[i][j]));
pat.add(next[i][j]);
pat.addAll(getMidPath(next[i][j],j));
return pat;
}
}
The tax is applied:
whenever any cargo passing through one city, except for the source and the destination cities.
So you if you have a path:
a -> b -> c -> d
Then you should include the cost of the path (a,b) + tax(b) + (b,c) + tax(c) + (c,d).
For implementing that into your algorithm, you should be able to add the city taxes to the path lengths like this:
If you know you're starting at a and ending at d, then any directed path to a city x, where x isn't a or b, should be treated as the cost of x + the tax at city x.
You will need to revert the path cost values back to the original ones for the next path you want to calculate the value of and re-add the tax values in for the new starting point and destination.

Categories