Related
Given an array of integers I need to find the maximum quantity of non zero elements between two zero elements
For example: int[] arr = {1,2,0,2,3,4,5,0,1,2,3,4,5,6,7,8,8,0,1}
This should return 9. However, this returns 4:
static int solution(int[] arr) {
int count = 0;
int maxCount = 0;
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] == 0 && i < arr.length - 2) {
i++;
while (arr[i] != 0) {
count++;
i++;
}
maxCount = count;
}
}
return maxCount;
}
UPD: For the case of {1,2,3,0,0,3,2,1}, function should return 0
Some issues:
The inner loop may run i out of the array's range.
When you find the ending zero, your code does not take into account that this zero is also the start of a new group, and "misses" it.
count is never reset to zero, so it keeps increasing also when you get into a second "group"
maxCount is set unconditionally, yet it should only be updated if the new count is greater than the count you already got.
There is no provision for when there is no group at all. I would suggest to return -1 in that case, so to differentiate it from the case where there is a group of length 0. This -1 should then be the initial value of the counts.
Also:
It is strange that the outer loop condition is made more strict by the if condition at the top of your loop. So why not make that i< arr.length-2 the loop condition?
Here is a correction of your attempt:
static int solution(int[] arr) {
int count = -1; // Start with invalid count
int maxCount = -1;
for (int i = 0; i < arr.length - 2; i++) { // Stricter loop condition
if (arr[i] == 0) {
count = 0; // Reset counter
// Safety & Look ahead for zero
while (i + 1 < arr.length && arr[i + 1] != 0) {
count++;
i++;
}
if (i + 1 >= arr.length) break; // No ending zero found
// Only update if improvement
if (count > maxCount) maxCount = count;
}
}
return maxCount;
}
You can however reduce the code a bit by using the outer loop to do the job of the inner loop:
static int solution(int[] arr) {
// Start with a count that can safely increment with `++` without getting positive
int count = -arr.length;
int maxCount = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
if (count > maxCount) maxCount = count;
count = 0; // Start of a potential new group
} else {
count++;
}
}
return maxCount;
}
And instead of maintaining count you could maintain the last starting index of a group:
static int solution(int[] arr) {
int start = arr.length; // Invalid start index
int maxCount = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
if (i - start > maxCount) maxCount = i - start;
start = i + 1;
}
}
}
This problem can be solved in a single pass. Observe the counts of non-zero elements when progressing from left to right:
1,2,0,2,3,4,5,0,1,2,3,4,5,6,7,8,8,0,1
- - 0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 0 1
Now consider the partial solution for the left subarray processed
1,2,0,2,3,4,5,0,1,2,3,4,5,6,7,8,8,0,1
- - 0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 0 1
0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 9 9
This tells you how to solve:
keep a counter of the number of non-zero elements since the previous zero. (Increment on nonzero, reset to zero on zero.)
keep the "answer" updated: every time you see a zero, keep the largest of the counter and the current answer, initially zero.
For the initial elements, it suffices to keep the count negative so that it does not influence the answer. A safe option is to initialize with minus the length of the list.
Technically, the loop is based on an invariant expressing that the counter holds the number of numbers since the previous zero (or a negative value), while answer holds the correct answer for the subarray traversed so far.
counter= - length(list)
answer= 0
for element in list:
if element == 0:
answer= max(counter, answer)
counter= 0
else:
counter= counter + 1
This will fix your all scenario,
Time complexity is O(n)
public static int maxCountBwZero(int arr[]) {
int i = 0;
int tempCount = 0;
int size = arr.length;
int maxCount = 0;
boolean startCount = false;
while (i < size) {
if (arr[i] == 0) {
if (maxCount == 0 && tempCount == 0) {
startCount = true;
} else {
if (tempCount > 0 && (tempCount >= maxCount)) {
maxCount = tempCount;
}
tempCount = 0;
}
} else if (startCount) {
tempCount++;
}
i++;
}
return maxCount;
}
public static void main(String[] args) {
int[] arr = { 1, 2, 0, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 1 };
int[] arr1 = { 1, 2, 3, 0, 0, 3, 2, 1 };
System.out.println(maxCountBwZero(arr));
System.out.println(maxCountBwZero(arr1));
}
I'm trying to program a solution to the 3sum question on leetcode(link: https://leetcode.com/problems/3sum/).
This is what I've done so far:
public int binary_search(int [] nums, int start, int end, int target)
{
if (start > end)
{
return -1;
}
int mid = (start + end) / 2;
if (nums[mid] == target)
{
return mid;
}
else {
if (nums[mid] < target)
{
return binary_search(nums, mid + 1, end, target);
} else {
return binary_search(nums, start, mid - 1, target);
}
}
}
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
ArrayList<List<Integer>> solution_set = new ArrayList();
Set<List<Integer>> ordered_solutions = new HashSet();
for (int i = 0; i < nums.length; i++)
{
if (i + 1 == nums.length)
{
continue;
}
int number_1 = nums[i];
int number_2 = nums[i+1];
int target = -(number_1 + number_2);
int target_index = binary_search(nums, 0, nums.length - 1, target);
if (binary_search(nums, 0, nums.length - 1, target) != -1 && target_index != i && target_index != i+1)
{
List<Integer> submission = new ArrayList();
submission.add(number_1); submission.add(number_2); submission.add(target);
List<Integer> ordered_submission = submission;
Collections.sort(ordered_submission);
if (ordered_solutions.add(ordered_submission) == true)
{
solution_set.add(submission);
}
}
}
return solution_set;
}
The program works as follows:
input is given to function threeSum which is then sorted and two following objects are created; An ArrayList that will store all non-duplicate solutions and a Set that is used to test for said duplicate solutions.
Then, the for loop sifts through the array and does the following:
it adds the i and i+1 element then negates them to find the number needed to sum all three numbers to zero. With this number acquired, a binary search is conducted on the array to see if this number can be found. If it is found, a few other conditions are tested to ensure that the target index is not actually the same as index i or i+1. After that, I create two objects, a submission that includes the elements in their original order and an ordered submission. If the ordered submission is inserted into the set and the set returns true, it means it's not a duplicate and i store it in the solution_set.
My problem is as follows: My program fails with the test case [0,0,0]. I believe the target is calculated as zero, but the binary search chooses the zero which is in i+1 so the solution is rejected. Does anyone have any suggestions on how this problem can be fixed?
Ok, if you want to do it with binary search, here it is. I've fixed several logical bugs, made some improvements, and added some comments, hope this will help. The code is accepted by leetcode, but it is not so efficient solution. Time complexity is O(n^2*logn). With 2 pointers approach you can do it in O(n^2).
public int binary_search(int[] nums, int start, int end, int target) {
if (start > end) {
return -1;
}
int mid = (start + end) / 2;
if (nums[mid] == target) {
return mid;
} else {
if (nums[mid] < target) {
return binary_search(nums, mid + 1, end, target);
} else {
return binary_search(nums, start, mid - 1, target);
}
}
}
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
ArrayList<List<Integer>> solution_set = new ArrayList<>();
// you can't do it using only one loop.
// Take a look at this sample input -2,0,1,1,2.
// Here you have to consider for nums[i] and nums[j] -2, 0 as well as
// -2, 1
for (int i = 0; i < nums.length - 2; i++) {
// skip duplicates
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for (int j = i + 1; j < nums.length - 1; j++) {
int number_1 = nums[i];
int number_2 = nums[j];
// skip duplicates and, since array is sorted, don't need to
// consider values > 0
if (i != j - 1 && nums[j - 1] == nums[j] || number_1 + number_2 > 0)
continue;
int target = -(number_1 + number_2);
// since array is sorted, start binary search only from j + 1
int target_index = binary_search(nums, j + 1, nums.length - 1, target);
if (target_index != -1) {
List<Integer> submission = new ArrayList<>();
submission.add(number_1);
submission.add(number_2);
submission.add(target);
solution_set.add(submission);
}
}
}
return solution_set;
}
Output:
[[0, 0, 0]]
[[-2, 0, 2], [-2, 1, 1]]
[[-1, -1, 2], [-1, 0, 1]]
I'm studying the 3 Sum to implement it on my own, and came across the following implementation with the rules:
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},
A solution set is:
(-1, 0, 1)
(-1, -1, 2)
And implementation (sorts the array, iterates through the list, and uses another two pointers to approach the target):
import java.util.*;
public class ThreeSum {
List<List<Integer>> threeSum(int[] num) {
Arrays.sort(num);
List<List<Integer>> res = new LinkedList<>();
for (int i=0; i<num.length-2; i++) {
if (i==0 || (i>0 && num[i] != num[i-1])) { //HERE
int lo = i+1;
int hi = num.length-1;
int sum = 0 - num[i];
while (lo < hi) {
if (num[lo] + num[hi] == sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
while (lo < hi && num[lo] == num[lo+1]) lo++; //HERE
while (lo < hi && num[hi] == num[hi-1]) hi--; //HERE
lo++; hi--;
} else if (num[lo] + num[hi] < sum) lo++;
else hi--;
}
}
}
return res;
}
//Driver
public static void main(String args[]) {
ThreeSum ts = new ThreeSum();
int[] sum = {-1, 0, 1, 2, -1, -4};
System.out.println(ts.threeSum(sum));
}
}
And my question is (located where commented: //HERE), what's the reason for checking num[i] != num[i-1], num[lo] == num[lo+1], and num[hi] == num[hi-1]? Supposedly they are supposed to skip the same result, but what does that mean? Examples would really help.
Thank you in advance and will accept answer/up vote.
Imagine you have {-1,-1,0,1,2,4} and considering triplet num[0], num[2], num[3] (-1,0,1).
lo=0 here. To exclude triplet num[1], num[2], num[3] with the same values, we should increment lo and pass over duplicate
This will prevent the list to have duplicate triplet.
For example, with you test :
int[] sum = {-1, 0, 1, 2, -1, -4};
will be sorted like :
sum = {-4, -1, -1, 0, 1, 2};
You see that you have -1 twice. Without these test, you would test twice if -1 = 0 + 1. This is not usefull so the algo simply search the next different value.
You could remove duplicate in the sorted List to prevent these test.
Thanks to MBo, we can't remove duplicate since we can have triplet with same value (but with different index)
All the three sentences is used to avoid the duplicate output.
Consider a sorted list {-2, -2 , 1, 1}
If there is no checking for num[i] != num[i-1], the output of the program would be(-2, 1, 1)and(-2, 1, 1), which are two duplicate triplets.
The checking for num[lo] != num[lo + 1]and num[hi] != num[hi - 1] are for the same reason.
Consider a sorted list
{-2,-1,-1,0,3}
If there is no checking for num[lo], you will get (-2,-1,3) and (-2,-1,3) as the output.
Still, I want to recommend a better solution for this problem. You can numerate the sum of two numbers in the list and find the 3rd number by hash or binary search. It will helps you to gain a O(n^2logn) time complexity rather than O(n^3). (I was wrong, the time complexity of this algorithm is O(n^2), sorry for that.)
Following program finds pairs of three integer with O(N*2)
Sort the input Array
and iterate each element in for loop and check for sum in program which is developed for Two sum.
Two sum in linear time after sorting ->
https://stackoverflow.com/a/49650614/4723446
public class ThreeSum {
private static int countThreeSum(int[] numbers) {
int count = 0;
for (int i = 0; i < numbers.length; i++) {
int front = 0, rear = numbers.length - 1;
while (front < rear) {
if (numbers[front] + numbers[rear] + numbers[i] == 0) {
System.out.printf(String.format("Front : {%d} Rear : {%d} I : {%d} \n", numbers[front],
numbers[rear], numbers[i]));
front++;
rear--;
count++;
} else {
if (Math.abs(numbers[front]) > Math.abs(numbers[rear])) {
front++;
} else {
rear--;
}
}
}
}
return count;
}
public static void main(String[] args) {
int[] numbers = { 1, 3, 5, 7, 12, 16, 19, 15, 11, 8, -1, -3, -7, -8, -11, -17, -15 };
Arrays.sort(numbers);
System.out.println(countThreeSum(numbers));
}
}
It's worked with any NSum (3Sum, 4Sum, 5Sum, ...) and quite fast.
public class ThreeSum {
private static final int RANDOM_RANGE = 20;
private Integer array[];
private Integer arrayIndex[];
private int result[];
private int bagLength;
private int resultIndex = 0;
private void generateData(int size) {
array = new Integer[size];
Random random = new Random();
for (int i = 0; i < size; i++) {
array[i] = random.nextInt(RANDOM_RANGE) - (RANDOM_RANGE/2);
}
}
private void markArrayIndex(int size) {
arrayIndex = new Integer[size];
for (int i = 0; i < size; i++) {
arrayIndex[i] = i;
}
}
private void prepareBeforeCalculate(int size, int sumExpected, int bagLength) {
this.bagLength = bagLength;
result = new int[bagLength];
generateData(size);
markArrayIndex(size);
}
void calculate(int size, int sumExpected, int bagLength) {
prepareBeforeCalculate(size, sumExpected, bagLength);
Arrays.sort(arrayIndex, (l, r) -> array[l].compareTo(array[r]));
System.out.println(Arrays.toString(array));
long startAt = System.currentTimeMillis();
if (sumExpected > 0) findLeft(sumExpected, 0, 0, array.length);
else findRight(sumExpected, 0, 0 - 1, array.length - 1);
System.out.println("Calculating in " + ((System.currentTimeMillis() - startAt) / 1000));
}
private void findLeft(int total, int indexBag, int left, int right) {
while (left < array.length && array[arrayIndex[left]] < 0 && indexBag < bagLength) {
navigating(total, arrayIndex[left], indexBag, left, right);
left++;
}
}
private void findRight(int total, int indexBag, int left, int right) {
while (right >= 0 && array[arrayIndex[right]] >= 0 && indexBag < bagLength) {
navigating(total, arrayIndex[right], indexBag, left, right);
right--;
}
}
private void navigating(int total, int index, int indexBag, int left, int right) {
result[indexBag] = index;
total += array[index];
if (total == 0 && indexBag == bagLength - 1) {
System.out.println(String.format("R[%d] %s", resultIndex++, toResultString()));
return;
}
if (total > 0) findLeft(total, indexBag + 1, left + 1, right);
else findRight(total, indexBag + 1, left, right - 1);
}
private String toResultString() {
int [] copyResult = Arrays.copyOf(result, result.length);
Arrays.sort(copyResult);
int iMax = copyResult.length - 1;
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(array[copyResult[i]]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
}
public class ThreeSumTest {
#Test
public void test() {
ThreeSum test = new ThreeSum();
test.calculate(100, 0, 3);
Assert.assertTrue(true);
}
}
I am trying to add two int arrays together to get a sum. The first array contains 0000000000000000123456789 and the second array contains 0001111111111111111111111. The sum should be 1111111111111234567900. Also I'm trying to do this without BigInteger or BigDecimal.
for(int i=0; i<number1.length;i++){
add= number1[i]+number2[i];
if(plus>=10){
sum[i-1]+=add/10;
sum[i] = add%10;
}else{
sum[i]=add;
}
}
The output that is produced at the moment is 00011111111111112345678100. How can I fix my code so that the 8 becomes a 9?
This kinda works. I can think of a couple of cases where something like this would break, like if the arrays were like {9,9,9} and {9,9,9}, result would be {9,9,8} instead of {1,9,9,8}. It's a minor fix that is being left as an activity to the reader.
public static void main(String []args){
int[] number1 = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9};
int[] number2 = {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
int carry = 0, sum = 0;
int[] result = new int[number1.length];
for (int i = number1.length - 1; i >= 0 ; i--) {
sum = number1[i] + number2[i] + carry;
result[i] = sum%10;
carry = sum/10;
}
// [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 9, 0, 0]
System.out.println(Arrays.toString(result));
}
Try this
int[] number = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9};
int[] number2 = {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
int[] result = new int[number.length+1];
int carry = 0;
for (int i = number.length - 1; i >= 0; i--) {
result[i+1] = number[i] + number2[i] + carry;
if (result[i+1] > 9) {
carry = result[i+1] - 9;
result[i+1] -= 10;
}
else {
carry = 0;
}
}
System.out.println(Arrays.toString(result));
This code should work for properly carrying numbers greater than 10 to the next up and keep the lower numbers!
int[] result = new int[number1.length+1];
for (int i=number1.length-1; i>=0;i--){
result[i+1] = number1[i] + number[i] + result[i+1];
if(result[i+1] >= 10){
result[i+1] -= 10; // it could never be more than 20 so this is ok and if it is 10 than it will still carry over to the next
result[i] = 1; // the ten carried to the next one
}
}
Similar to Seek Addo's answer, but avoids the errors found in his code that prevent the application from properly carrying the numbers.
This is the most compact way I could think to do it, and should yield the proper answers of
[1,1,1,1,1,1,1,1,1,1,1,1,1,2,3,4,5,6,7,9,0,0] or 1111111111111234567900
The accepted answer is not good. This is my version of it (support for different array sizes):
public static int[] sumIntArrays(int[] n1, int[] n2) {
int n1Size = n1.length - 1, n2Size = n2.length - 1, indexSum = n1Size > n2Size ? n1Size + 2 : n2Size + 2, slack = 0, s;
int[] sum = new int[indexSum];
while (true) {
if (n1Size < 0 && n2Size < 0)
break;
s = (n1Size < 0 ? 0 : n1[n1Size--]) + (n2Size < 0 ? 0 : n2[n2Size--]) + slack;
if (s > 9) {
sum[--indexSum] = s % 10;
slack = s / 10;
} else {
sum[--indexSum] = s;
slack = 0;
}
}
if (slack != 0)
sum[0] = slack;
return sum;
}
I have a specific amount of numbers. Now I want to somehow display all possible permutations of this sequence.
For example if the amount of numbers is 3, I want to display:
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 1 2
0 2 0
0 2 1
0 2 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 1 2
1 2 0
1 2 1
1 2 2
2 0 0
2 0 1
2 0 2
2 1 0
2 1 1
2 2 0
2 2 1
2 2 2
I have this code to do that where depth is the amount of numbers. Obviously this code isn't working correct. Any hints how to improve?:
for (int i = 0; i < (depth * depth); i++) {
path = setPath(depth, path, i);
print(path);
}
private static int[] setPath(int depth, int[] path, int i) {
for (int j = 1; j <= depth; j++) {
if (j == 1) {
path[depth-1] = i%depth;
} else {
path[depth-j] = i / ((j-1)*depth);
}
}
return path;
}
Here is some code:
public static void main(String[] args) throws IOException {
List<Number> list = new ArrayList<Number>();
list.add(0);
list.add(1);
list.add(2);
printCombinations(new ArrayList<Number>(), list, 0);
}
public static void printCombinations(List<Number> done, List<Number> numbers, int depth) {
if (numbers.size() <= depth) {
System.out.println(done); // replace with something better
} else {
for (Number r : numbers) {
List<Number> newDone = new ArrayList<Number>(done);
newDone.add(r);
printCombinations(newDone, numbers, depth + 1);
}
}
}
Prints exactly what you asked, for any number of any numbers. :)
You want to print permutations with length 3 of the 3 objects {0, 1, 2} allowing for repetitions. You have 3^3 of such permutations. So, the first problem with your code, is that the loop for (int i = 0; i < (depth * depth); i++) { ... } should actually count from 0 to Math.pow(depth, depth). Then, a couple of remarks on the function setPath(...):
rather than passing path as a parameter, you'd better create a path and return it
what you want to do in setPath is convert i into base depth: for example, when i is 12, you want to return [1, 1, 0], and 110 in base 3 (your depth) is 13 in base 10
Here's your code with the changes above:
public static void main(String[] args) {
int depth = 3;
for (int i = 0; i < Math.pow(depth, depth); i++) {
int[] path = setPath(depth, i);
System.out.println(Arrays.toString(path));
}
}
private static int[] setPath(int depth, int i) {
int[] path = new int[depth];
int num = i;
int length = path.length - 1;
int index = 0;
while (num != 0) {
int remainder = num % depth;
num = num / depth;
path[length - index] = remainder;
index++;
}
return path;
}
An alternative recursive approach is:
public static void main(String[] args) {
int depth = 3;
for (int i = 0; i < Math.pow(depth, depth); i++) {
System.out.println(pad(convert(i, depth), depth));
}
}
private static String pad(String s, int b) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i <= b - s.length() - 1; i++) sb.append(0);
sb.append(s);
return sb.toString();
}
private static String convert(int n, int b) {
if (n < b)
return String.valueOf(n);
else
return convert(n / b, b) + String.valueOf(n % b);
}
where convert performs the base conversion.
I think you can have a more efficient algorithm which count modulo depth form 0 to depth^depth. I have a similar algorithm for printing the elements of a cartesian product, and your problem is actually equivalent to printing the elements of the cartesian product {0, 1, 2} x {0, 1, 2} x {0, 1, 2}.
I hope this helps.
If you want to find all possible permutations for a non-specific length of numbers then you should use a recursive algoritm.
I designed an approach according to that:
Let's accept that count is 3 at your example. This numbers seems like writing numbers from 0 to maximum count -at base count- with number of count step(_ , _ , _) so:
public static void main(String[] args) {
startAlgorithm(3);
}
public static void startAlgorithm(int count){
int start = 0;
int max = (int) (Math.pow(count, count) - 1);
for (int number = start; number <= max; number++) {
int[] printTo = new int[count];
int tempNum = number;
for (int i = 0; i < count; i++) {
int printInt = tempNum % count;
printTo[count - i - 1] = printInt;
tempNum /= count;
}
for (int y = 0; y < count; y++) {
System.out.print(printTo[y]);
}
System.out.println();
start++;
}
}
This solution works for every number you give as a parameter to your function and exactly prints what you want.
Did you look at the wikipedia page on permutations? There's at least one algorithm spelled out there.