Java grouping algorithm - java

Given an array of ints, is it possible to choose a group of some of the ints, such that the group sums to the given target, with this additional constraint: if there are numbers in the array that are adjacent and the identical value, they must either all be chosen, or none of them chosen. For example, with the array {1, 2, 2, 2, 5, 2}, either all three 2's in the middle must be chosen or not, all as a group. (one loop can be used to find the extent of the identical values).
The test scenarios are below
groupSumClump(0, {2, 4, 8}, 10) → true true OK
groupSumClump(0, {1, 2, 4, 8, 1}, 14) → true true OK
groupSumClump(0, {2, 4, 4, 8}, 14) → false false OK
groupSumClump(0, {8, 2, 2, 1}, 9) → true false X --->Failing
groupSumClump(0, {8, 2, 2, 1}, 11) → false false OK
groupSumClump(0, {1}, 1) → true false X --->Failing
groupSumClump(0, {9}, 1) → false false OK
other tests OK
Snippet is as below
private int sum(final Integer start, final Collection<Integer> list) {
int sum = start;
for (final int i : list) {
sum += i;
}
return sum;
}
public boolean groupSumClump(final int start, final int[] nums, final int target) {
for (int i = 0; i < nums.length-1; i++) {
if(nums[i] == nums[i+1]){//group selected logic
int sum = nums[i] + nums[i+1];//is this Ok ?
nums[i] =sum;
nums[i+1]=0;
}else{
//how to handle the logic for group not selected.
}
}
final List<Integer> fixed = new ArrayList();
final List<Integer> candidates = new ArrayList();
// fills candidates and fixed
for (int i = 0; i < nums.length; i++) {
final int cand = nums[i];
if (cand == 1 && i > 0) {
final int prev = nums[i - 1];
}else if (cand < target) {
candidates.add(cand);
}
}
// compute the sum of fixed
final int sumFixed = sum(0, fixed);
// if the sum of fixed is equals to target we don't need to do
//anything because we already know we need to return true.
if (sumFixed == target) {
return true;
}
if (sumFixed <= target && !candidates.isEmpty()) {
final Set<Set<Integer>> powerSets = powerSet(new HashSet(candidates));
for (final Set<Integer> set : powerSets) {
if (sumFixed + sum(0, set) == target) {
return true;
}
}
}
return false;
}
public <T> Set<Set<T>> powerSet(Set<T> originalSet) {
Set<Set<T>> sets = new HashSet<Set<T>>();
if(originalSet.isEmpty()) {
sets.add(new HashSet<T>());
return sets;
}
List<T> list = new ArrayList<T>(originalSet);
T head = list.get(0);
Set<T> rest = new HashSet<T>(list.subList(1, list.size()));
for (Set<T> set : powerSet(rest)) {
Set<T> newSet = new HashSet<T>();
newSet.add(head);
newSet.addAll(set);
sets.add(newSet);
sets.add(set);
}
return sets;
}
could you let me whats the problem with the code and why is it failing for test scenarios as mentioned.
i want to know what is the logic for group not selected?

Here is the full solution which passes all your test cases.
Please edit yourself to make it fit to your APIs ^_^
public static void main(String[] args) {
int nums [] = new int[]{2, 4, 8};
int target = 10;
int nums_another [] = grouped (nums);
System.out.println(viable(0, nums_another, 0, target));
}
private static int [] grouped (int nums []) {
int nums_another[] = new int [nums.length];
int i = 0;
int j = 0;
i++;
int c = 1;
while (i < nums.length){
if (nums[i] == nums[i-1]) { // count identical numbers
c++;
}
else { // not identical, store sum of previous identical numbers (possibly only 1 number)
if (nums[i-1] != 0) {
nums_another[j] = nums[i-1] * c;
j++;
}
c = 1;
}
i++;
}
if (nums[i-1] != 0) { // store last
nums_another [j] = nums[i-1] * c;
}
return nums_another;
}
/* partial_sum + sub array of "array from start to 0's" -> target */
private static boolean viable (int partial_sum, int array[], int start, int target) {
if (partial_sum == target) {
return true;
}
else if (start >= array.length || array[start] == 0) {
return false;
}
else { // Key step
return viable (partial_sum + array[start], array, start + 1, target)
|| viable (partial_sum, array, start + 1, target);
}
}
Key step:
return whether target is viable through sub array, test both cases start is included or not.

One helpful first step would be to replace the array with a LinkedMultiSet. Not a standard runtime collection but easy enough to imagine, find an implementation, or make.

Related

isSorted? Check array if is sorted in ascending or descending order in Java

can someone help me check my codes if are right or help me know if there is any other is way to solve this question I was trying to check if an array is in ascending or descending order then return 1 if not then return 0; at first I created some method for sorting array in increasing order and order and another method for decreasing and then I used those method to compare with the original array if it is sorted. I used the code below:
public class IsSorted {
public static void main(String[] args){
int[] list ={4,3,2,1};
System.out.println(isSorted(list));
}
public static int isSorted(int[] a){
if(a.length==0){
return 1;
}
if(a.length==1){
return 1;
}
int[] holdingArray=new int[a.length];
for (int i =0; i<a.length; i++){
holdingArray[i]=a[i];
}
int[] virtualIncreasedArray= new int[holdingArray.length];
int[] virtualDecreasedArray= new int[holdingArray.length];
sortIncrease(holdingArray);
for(int i=0; i<holdingArray.length;i++){
virtualIncreasedArray[i]=holdingArray[i];
}
sortDecrease(holdingArray);
for(int i=0; i<holdingArray.length;i++){
virtualDecreasedArray[i]=holdingArray[i];
}
//check if array is decreasing
for(int i=0; i<virtualDecreasedArray.length;i++){
if(virtualDecreasedArray[i]!=a[i]&&virtualIncreasedArray[i]!=a[i]){
return 0;
}
}
//check if array is increasing
return 1;
}
static void sortIncrease(int[] a){
for(int unsorted=a.length-1; unsorted>0; unsorted--){
for(int i=0; i<unsorted;i++){
if(a[i]>a[i+1]){
swap(a,i,i+1);
}
}
}
}
static void sortDecrease(int[] a){
for(int unsorted=a.length-1; unsorted>0; unsorted--){
for(int i=0; i<unsorted; i++){
if(a[i]<a[i+1]){
swap(a,i,i+1);
}
}
}
}
static void swap(int[] a, int i, int j){
if(i==j){
return;
}
int temp = a[i];
a[i]=a[j];
a[j]=temp;
}
}
For an accurate verification, the following should be done as there are important side cases to consider.
Checking if any list starts out with some number of equal values.
Determine the starting index where the values first differ.
If all the values are equal, return true immediately.
Note that in the worst case when all the values are equal, the entire array needs to be checked (sans the last value since then it could be either ascending or descending).
int[] sortedAscending = { 1, 1, 3, 4, 7, 10, 11, 15, 15 };
int[] sortedDescending = { 22, 22, 12, 8, 8, 8, 5, 2, 1 };
int[] sortedBoth = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int[] unsorted = { 2, 1, 2, 19, 19, 2, 4 };
System.out.println(isSorted(sortedAscending));
System.out.println(isSorted(sortedDescending));
System.out.println(isSorted(sortedBoth));
System.out.println(isSorted(unsorted));
Prints
true
true
true
false
The check method.
public static boolean isSorted(int[] arr) {
int start = 0;
// if the lists start with equal values, need to
// determine a starting point.
while (arr[start] == arr[start+1]
&& start++ < arr.length - 2);
if (start >= arr.length - 2) {
// all but the last the same value, its sorted
return true;
}
boolean asc = arr[start] < arr[start + 1];
for (int i = start; i < arr.length - 1; i++) {
if (asc) {
//check ascending
if (arr[i] > arr[i + 1]) {
return false;
}
// check descending
} else if (arr[i] < arr[i + 1]) {
return false;
}
}
return true;
}
Since you asked for another way to do this, here is a different approach.
What you could do is:
Determine whether the array is (supposedly) sorted in ascending or descending order based on the first 2 elements (if these exist)
Consider equal values when determining the supposed sorting (thanks for pointing that out #WJS)
Then, check the rest of the array for the correct order, based on what was determined
Updated Example:
public static void main(String[] args) {
int[] sortedAsc = { 1, 2, 3, 4, 5 };
int[] sortedDesc = { 5, 4, 2, 1 };
int[] unsortedArray = { 1, 8, 2, 4 };
int[] allEqual = { 3, 3, 3, 3, 3 };
int[] firstEqual = { 2, 2, 3, 2 };
System.out.println(isSorted(sortedAsc));
System.out.println(isSorted(sortedDesc));
System.out.println(isSorted(unsortedArray));
System.out.println(isSorted(allEqual));
System.out.println(isSorted(firstEqual));
}
public static boolean isSorted(int[] arr) {
boolean isAscending = false;
if (arr.length < 2) { // if the array has less than 2 elements, must be sorted
return true;
}
if (arr[0] < arr[1]) { // do we think this array is sorted ascending?
isAscending = true;
} else {
int index = 0;
while (arr[index] == arr[index + 1] && index++ < arr.length - 2) {
// keep checking for sorting if array consists of equal values
if (index >= arr.length - 2) {
return true; // whole array consists of equal values
}
}
// now that equal values were skipped, check for sorting again
isAscending = arr[index] < arr[index + 1];
}
// check all elements of the array
for (int i = 0; i < arr.length - 1; i++) {
if (isAscending) {
if (arr[i] > arr[i + 1]) {
return false;
}
} else {
if (arr[i] < arr[i + 1]) {
return false;
}
}
}
return true;
}
Output:
true
true
false
true
false
Sidenotes for your code:
Instead of returning an int (0, 1), your isSorted() method should definitely return boolean.
There is no point in the holdingArray.

Java alternance method not working

I have an integer array and I want to check if any two successive elements have different signs. I tried this, but it doesn't work
For example, {2,-3,17,-1,4,5,-1,8,-9,3} must be false but the method gives true
public boolean alternance(int[] a) {
for(int i = 0; i < a.length - 1; i++) {
if(a[i] * a[i+1] < 0)
return true;
}
return false;
}
I'm not sure if it is exactly what are you looking for but below method will return false for {2,-3,17,-1,4,5,-1,8,-9,3}
public boolean alternance(int[] a) {
boolean isAlternance = true;
for(int i = 0; i < a.length - 1; i++) {
if(a[i] * a[i+1] >= 0)
isAlternance = false;
}
return isAlternance;
}
Obligatory recursive solution
public class TestStackOverflowQuestion {
// An array with 0 or 1 elements doesn't have alternating signs
// An array has alternating signs if the next element has a different
// sign as the current element, and if that's true for the rest of the array
public static boolean alternance (int[] arr, int pos) {
if (arr.length <= 1) return false;
return (pos == arr.length - 1) ||
(Math.signum(arr[pos]) != Math.signum(arr[pos + 1])
&& alternance(arr, pos + 1)
);
}
public static void main(String[] args) {
int[] array = {};
System.out.println(alternance(array, 0)); // false
int[] array2 = {1};
System.out.println(alternance(array2, 0)); // false
int[] array3 = {1, -2, 3, -4};
System.out.println(alternance(array3, 0)); // true
int[] array4 = {-1, -2, 3, -4};
System.out.println(alternance(array4, 0)); // false
int [] array5 = {2,-3,17,-1,4,5,-1,8,-9,3};
System.out.println(alternance(array5, 0)); // false
int[] array6 = {12,-3,3,-8,33,-2,1,-8,11,-3};
System.out.println(alternance(array6, 0)); // true
}
}

How to iterate over array of integers to find a sequence based on an O(N) solution?

I saw following question and tried to find an answer for that.
Question: Given a sequence of positive integers A and an integer T, return whether there is a *continuous sequence* of A that sums up to exactly T
Example
[23, 5, 4, 7, 2, 11], 20. Return True because 7 + 2 + 11 = 20
[1, 3, 5, 23, 2], 8. Return True because 3 + 5 = 8
[1, 3, 5, 23, 2], 7 Return False because no sequence in this array adds up to 7
Note: We are looking for an O(N) solution. There is an obvious O(N^2) solution which is a good starting point but is not the final solution we are looking for.
My answer to above question is:
public class Tester {
public static void main(String[] args) {
int[] myArray = {23, 5, 4, 7, 2, 11};
System.out.println(isValid(myArray, 20));
}
public static boolean isValid(int[] array, int sum) {
int pointer = 0;
int temp = 0;
while (pointer < array.length)
{
for (int i = pointer; i < array.length; i++)
{
if (array[i] > sum)
break;
temp += array[i];
if (temp == sum)
return true;
else if (temp > sum)
break;
// otherwise continue
}
temp = 0;
pointer++;
}
return false;
}
}
I think my answer is O(N^2) which is not acceptable based on Question. Is there a solution based on O(N)?
You only need to loop once actually which is O(N).
Start adding from index 0 and once you exceed the sum start removing from the beginning of the array. if temp falls below sum continue looping.
public static boolean isValid(int[] array, int sum) {
int init = 0,temp = 0;
for (int i = 0; i < array.length; i++) {
temp += array[i];
while (temp > sum) {
temp -= array[init];
init++;
}
if (temp == sum)
return true;
}
return false;
}
What you should do is to have two indices (start and stop) then you increase stop until the sum is the required (and return true) or above. Then you increase start until the sum is the required (and return true or below. Then you repeat this until you reach the end of the array. You can update the sum incrementally (add the element when you increase stop and subtract when you increase start). This ought to be O(N).
Here's an example:
public class t {
public static void main(String[] args) {
int[] myArray = {23, 5, 4, 7, 2, 11};
System.out.println(isValid(myArray, 20));
}
public static boolean isValid(int[] array, int sum) {
int start = 0;
int stop = 0;
int tsum = 0;
while( true )
{
if( tsum < sum )
{
if( stop >= array.length )
break;
tsum += array[stop];
stop++;
}
else if( tsum > sum )
{
tsum -= array[start];
start++;
}
else if( tsum == sum )
return true;
// System.out.println(start + " -- " + stop + " => " + tsum);
}
return false;
}
}

A recursive algorithm to find every possible sum given an integer array?

So given an array for example [3, 5, 7, 2] I want to use recursion to give me all the possible combinations of sums, for example: 3, 5, 7, 2, 8(3+5),10(3+7),5(3+5)... 15(3+5+7) etc. I'm not exactly sure how to go about this using java.
You have two choice with each number in the array.
Use the number
Don't use the number
void foo(int[] array, int start, int sum) {
if(array.length == start) return;
int val = sum + array[start];
//print val;
foo(array, start + 1, val); //use the number
foo(array, start + 1, sum); //don't use the number
}
the initial call is foo(a, 0, 0)
An recursive algorithm for this could work as follows:
All the sums for a list equals the union of:
The first number plus the sums of the sublist without the first number
The sums of the sublist without the first number
Eventually your recursive call will hit the stopping condition of an empty list, which has only one sum(zero)
Here's one way of doing it in pseudo code:
getAllPossibleSums(list)
if(list.length == 1)
return list[0];
otherSums = getAllPossibleSums(list[1:end])
return union(
otherSums, list[0] + otherSums);
public static void main(String[] args) {
findAllSums(new int[] {3, 5, 7, 2}, 0, 0);
}
static void findAllSums(int[] arrayOfNumbers, int index, int sum) {
if (index == arrayOfNumbers.length) {
System.out.println(sum);
return;
}
findAllSums(arrayOfNumbers, index + 1, sum + arrayOfNumbers[index]);
findAllSums(arrayOfNumbers, index + 1, sum);
}
You have two branches, one in which you add the current number and another in which you don't.
public static void main(String[] args) {
int [] A = {3, 5, 7, 2};
int summation = recursiveSum(A, 0, A.length-1);
System.out.println(summation);
}
static int recursiveSum(int[] Array, int p, int q) {
int mid = (p+q)/2; //Base case
if (p>q) return 0; //Base case
else if (p==q) return Array[p];
**else
return recursiveSum(Array, p, mid) + recursiveSum(Array, mid + 1, q);**
}
Simplest way ever:
private int noOfSet;
Add below method:
private void checkSum() {
List<Integer> input = new ArrayList<>();
input.add(9);
input.add(8);
input.add(10);
input.add(4);
input.add(5);
input.add(7);
input.add(3);
int targetSum = 15;
checkSumRecursive(input, targetSum, new ArrayList<Integer>());
}
private void checkSumRecursive(List<Integer> remaining, int targetSum, List<Integer> listToSum) {
// Sum up partial
int sum = 0;
for (int x : listToSum) {
sum += x;
}
//Check if sum matched with potential
if (sum == targetSum) {
noOfSet++;
Log.i("Set Count", noOfSet + "");
for (int value : listToSum) {
Log.i("Value", value + "");
}
}
//Check sum passed
if (sum >= targetSum)
return;
//Iterate each input character
for (int i = 0; i < remaining.size(); i++) {
// Build list of remaining items to iterate
List<Integer> newRemaining = new ArrayList<>();
for (int j = i + 1; j < remaining.size(); j++)
newRemaining.add(remaining.get(j));
// Update partial list
List<Integer> newListToSum = new ArrayList<>(listToSum);
int currentItem = remaining.get(i);
newListToSum.add(currentItem);
checkSumRecursive(newRemaining, targetSum, newListToSum);
}
}
Hope this will help you.

Arrays in Java - Core Java

In This Question A value is "everywhere" in an array if for every pair of adjacent elements in the array, at least one of the pair is that value. Return true if the given value is everywhere in the array.
isEverywhere({1, 2, 1, 3}, 1) → true,coz 1 is present in(1,2) and (1,3)
isEverywhere({1, 2, 1, 3}, 2) → false,coz 2 is in (1,2) but not in (1,3)
isEverywhere({1, 2, 1, 3, 4}, 1) → false,coz 1 is present in 2 pairs (1,2) and (1,3) but 4 is not having a pair of 1
My Partial working code is below,could you help me out with this problem,stuck up for a long time.
::Code::
public boolean isEverywhere(int[] nums, int val) {
boolean flag = false;
for(int i=0;i<nums.length;i++){
for(int j=i+2;j<nums.length;j++){
if(nums[i] == nums[j]){
flag = true;
}
}
}
return flag;
}
Result expected:
`Expected` `This` `Run`
isEverywhere({1, 2, 1, 3}, 1) → true true OK
isEverywhere({1, 2, 1, 3}, 2) → false true X
isEverywhere({1, 2, 1, 3, 4}, 1) → false true X
Try this:
boolean isEverywhere(int[] nums, int val) {
// use i+=2 to get start index of pair.
for(int i=0;i<nums.length;i+=2) {
// other index in the pair.
int j = i + 1;
// make sure the other index really exists.
if(j < nums.length) {
// if it exists..and val is not equal to
// either in the pair..return false.
if(nums[i] != val && nums[j] != val) {
return false;
}
} else {
// no pair..one element case.
// return true if that element is val..else return false.
return nums[i] == val;
}
}
// array has no unpaired element..and all pairs have val.
return true;
}
The key is
for every pair of adjacent elements in the array
Print out i and j before if(nums[i] == nums[j]) and you'd see what's going on.
For an array of length 2, you need (0, 1), for array of length 3, you need (0, 1), (1, 2), and so on.
You never use val in your code
Try figuring out the logic for that first
And this can be done with a single loop, try to figure out how you would as a person apply an algorithm, then code it
Your code is failing because the flag does not turn off in the case that the second loop goes beyond the array length.
Not a full solution, but if the length of the array is odd, check that the last value equals the target val
...
if( !(nums.length % 2) == 0 ){
if( nums[length-1] != val){
return false;
}
}
...
I did mine by simply counting if there are spaces:
Here it is in it's simple glory:
public boolean isEverywhere(int[] nums, int val) {
//Create an int to count the number of spaces between each instance of val.
int counter = 0;
//Create a for loop that checks val;
for (int i = 0; i < nums.length; i++)
{
//If the number at iteration i != val;
if (nums[i] != val)
{
//We increment the counter by one.
counter++;
}
//If the number does equal val, we put the counter back to 0;
else
{
counter = 0;
}
//If the counter is greater than or equal to two,
//We know that there is a space of more than 2, and so
//We return false;
if (counter >= 2)
{
return false;
}
}
//Return true if not false;
return true;
}
This code works fine:-
public boolean isEverywhere(int[] nums, int val) {
for(int i=0;i<=nums.length-2;i++){
if(nums[i]!=val&&nums[i+1]!=val){
return false;
}
}
return true;
}
public class IE {
static boolean isEverywhere(int[] a, int val) {
for (int i = 0; i < a.length; i++) {
System.out.println("*** iteration: " + i);
System.out.println("a[" + (i-1) + "]=" + (i > 0 ? a[i-1] : "n/a"));
System.out.println("a[" + i + "]=" + a[i]);
System.out.println("a[" + (i+1) + "]=" + (i < a.length -1 ? a[i+1] : "n/a"));
if (a[i] != val && (i > 0 ? a[i-1] != val : true) && (i < a.length-1 ? a[i+1] != val : true)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
int[] a = new int[] {1, 2, 1, 3};
System.out.println(isEverywhere(a, 1));
a = new int[] {1, 2, 1, 3};
System.out.println(isEverywhere(a, 2));
a = new int[] {1, 2, 1, 3, 4};
System.out.println(isEverywhere(a, 1));
}
}
Basically, for a given element in the array, the test fails if the value isn't adjacent, either before or after it.

Categories

Resources