I am trying to come up with an algorithm in Java which when given a string of digits can identify a combination of integers which meets the following criteria
N = N1 + N2
N >= N1 >= N2
where:
N is the Nth element in the string or element at Nth position;
N1 is the (N-1) element in the string & N2 is the (N-2) element in the string.
Example 1: 224610
Elements in this string are 2, 2, 4, 6, 10.
First Set: 2+2=4 (N2=2; N1=2 & N= 4);
Second Set: 2+4=6 (N2=2; N1=4 & N=6);
Third Set: 4+6=10 (N2=4; N1=6 & N= 10)
Example 2: 11112233558
Elements in this string are 1, 11, 12, 23, 35, 58
Example 3: 1101102203
Elements in this string are 1, 101, 102, 203.
I have already written a function which can take an ArrayList of integers and tell you whether the array complies with the requirements.
public static boolean complies(ArrayList<Integer> al)
{
boolean result = true;
int alsize = al.size();
for (int n = alsize-1; n > 1; n--)
{
int N1 = al.get(n-1);
int N2 = al.get(n-2);
int N = al.get(n);
if (N != ( N1 + N2))
result = false;
if ((N < N1) || (N1 < N2))
result = false;
}
return(result);
}
The part I am struggling with his finding an elegant way to identify all possible integer combinations which I can run through the above function.
I thought about the question you asked, which was essentially how to find all the combinations of a set of digits in the order the digits were given, and realized that this could be solved recursively. All you have to do is add the first digit to all the combinations that can be made with the rest of the digits as well as put that digit in front of the first term of all the combinations. The base case is that there is only one digit, which means there is of course only one combination.
Let me give an example. With the digits 123 first we find all the combinations for 23 and since 23 has more than one digit we find all the combos for 3, which is just 3. Then add 2 to that combination which makes 2, 3 and put 2 in front of the first term of that combination, which makes 23. Now add 1 to all the combos which makes 1, 2, 3 and 1, 23 and put 1 in front of the first term which makes 12, 3 and 123.
So I made this method to find all the combinations. It returns a two dimensional arrayList with each individual arrayList being a unique combination. The preconditions are that you have to give it a string of numbers only and no empty strings. If I made a mistake or it doesn't work for your application say something. I am pretty sure you could just go through the two dimensional arrayList and check if each arrayList works in your boolean method. You can test it here.
public ArrayList<ArrayList<Integer>> findCombos(String input)
{
ArrayList<ArrayList<Integer>> answer = new ArrayList<ArrayList<Integer>>();
if(input.length()==1)
{
ArrayList<Integer> combo = new ArrayList<Integer>();
answer.add(combo);
combo.add(Integer.parseInt(input)); //this method converts from a string to an int
return answer;
}
else
{
answer = findCombos(input.substring(1));
int size = answer.size(); //you need to save this because when you add things to an arrayList the size changes
for(int i=0;i<size;i++) //this copies the arrayList back to itself
{
ArrayList<Integer> copy = new ArrayList<Integer>(answer.get(i));
answer.add(copy);
}
int digit = (char)(input.charAt(0)-'0');//this saves the current digit
for(int i=0;i<size;i++)//this adds the digit in front of all the previous combos
answer.get(i).add(0, digit);
for(int i=size;i<answer.size();i++)//this puts the digit in front of the first term of the previous combos
{
String copy = "" + answer.get(i).get(0);//I just did this to find the length of the first term easily
int append = (int)(digit*Math.pow(10, copy.length()));
answer.get(i).set(0, append+answer.get(i).get(0));
}
return answer;
}
}
The Code below works against all 3 given input, and is solid enough.
public class IntFinder
{
/**
* #param args the command line arguments
*/
private static String given = "444444889321420";
static N1N2 temp = new N1N2(given);
public static void main(String[] args) {
// TODO code application logic here
N1N2 n1 = new N1N2(given);
N1N2 n2 = new N1N2(given);
/*IntFinder.setGiven("224610");
n1 = new N(IntFinder.getGiven());
n2 = new N(IntFinder.getGiven());
n1.setValue(0, 0); // 2
n2.setValue(1, 1); // 2*/
/*IntFinder.setGiven("11112233558");
n1 = new N(IntFinder.getGiven());
n2 = new N(IntFinder.getGiven());
n1.setValue(0, 0); // 1
n2.setValue(1, 2); // 11*/
IntFinder.setGiven("1101102203");
n1 = new N1N2(IntFinder.getGiven());
n2 = new N1N2(IntFinder.getGiven());
n1.setValue(0, 0); // 1
n2.setValue(1, 3); // 101
System.out.println("string: " + n1.getValue());
System.out.println("string: " + n2.getValue());
System.out.println("result: " + ((IntFinder.findTillEndByN1N2(n1, n2) > -1) ? "found" : "NOT found"));
}
public static String setGiven(String givenString)
{
return IntFinder.given = givenString;
}
public static String getGiven()
{
return IntFinder.given;
}
public static int findTillEndByN1N2(N1N2 n1, N1N2 n2)
{
int retVal = -1, lenChange = n1.getLength() + n2.getLength() + n1.getStartIndex();
retVal = findNagainstN1N2(n1, n2, lenChange);
if (IntFinder.getGiven().length() == (n2.getEndIndex() + 1)) // base case 1 (last digit reached)
{
return 1;
}
else if (IntFinder.getGiven().length() < (n2.getEndIndex() + 1))
{
System.out.println("fatal err:");
System.exit(0);
}
if (retVal > -1) // recurse till end
{
if (!temp.getUsed())
{
temp = IntFinder.shallowCopy(n1);
temp.setUsed(true);
}
n1 = IntFinder.shallowCopy(n2);
n2.setValue(n2.getEndIndex() + 1 , retVal);
System.out.println("string: "+n2.getValue());
retVal = findTillEndByN1N2(n1, n2);
}
else
return retVal;
return retVal;
}
public static Integer findNagainstN1N2(N1N2 n1, N1N2 n2, Integer startIndex)
{
String remainingGiven = IntFinder.getGiven().substring(startIndex);
Integer i, n1n2Total = 0, retVal = -1;
n1n2Total = n1.getValue() + n2.getValue();
for (i = 0; i < remainingGiven.length(); i++)
{
try
{
int found = Integer.parseInt(remainingGiven.substring(0, (i+1)));
if (found == n1n2Total)
{
retVal = startIndex + i;
break;
}
else if (found > n1n2Total)
{
retVal = -1;
break;
}
}
catch (NumberFormatException e)
{
;
}
}
return retVal;
}
public static N1N2 shallowCopy(N1N2 from) {
N1N2 newN = new N1N2(IntFinder.getGiven());
newN.setValue(from.getStartIndex(), from.getEndIndex());
return newN;
}
}
>>N1N2.class
public class N1N2 {
private String givenString;
private int startIndex = 0;
private int endIndex = -1;
private int value = 0;
private int length = endIndex + 1;
private Boolean used = false;
public N1N2(String given) {
startIndex = 0;
endIndex = given.length() - 1;
givenString = given;
}
public int getValue() {
return value;
}
public int getLength() {
return length;
}
public Boolean getUsed()
{
return used;
}
public void setUsed(Boolean used)
{
this.used = used;
}
// public void outValues()
// {
// System.out.println("given:" + givenString + ", startIndex:"+ startIndex + ", endIndex: " + endIndex + ", length:" + length + ", value:" + value + "\n");
// }
public void setValue(int startIndex, int endIndex) {
this.value = Integer.parseInt(givenString.substring(startIndex, endIndex + 1));
this.startIndex = startIndex;
this.endIndex = endIndex;
this.length = (this.value + "").length();
// this.outValues();
}
public int getEndIndex() {
return this.endIndex;
}
public int getStartIndex() {
return this.startIndex;
}
}
Just set n1 and n2 properly before calling IntFinder.findTillEndByN1N2(n1, n2).
Observe the examples I used.
So to complete the program, create your own algorithm using two loops filling
n1.setValues and n2.setValues
Ex.
given = 1232447
//first loop
n1.setValues(0,0) // value = 1
n2.setValues(1,1) // value = 2
IntFinder.findTillEndByN1N2(n1, n2) // returns -1 // not found...
//next loop - increment n2 length
n1.setValues(0,0) // value = 1
n2.setValues(1,2) // value = 23
IntFinder.findTillEndByN1N2(n1, n2) // returns 1 // now found till end.
//ofcourse when n2 reached the last digit, increment n1 length by 1 and set n2 length back to 1.
//for given=444444889321420 // 44 444 488 932 1420
//all findTillEnd with n1 length 1 should fail so inc n1 length on outer loop
//n1.setValue(0, 1) // 2 digit number ( 44)
//n2.setValue(0, 0) // 4
//upon continuing loop, the desired result will be met.
In line with the above solution from Pham I could modify the code to exclude the edge cases and create a solution for the above question.This method will always return true if it complies with the pattern else false and yes we have to find first two elements to make it work.Checked for all test cases :
public static boolean complies(String input){
// List<Long> firstTwo = new ArrayList<Long>();
for(int i = 1; i < input.length(); i++){
for(int j = 0; j < i; j++){
long first = Long.parseLong(input.substring(0, j + 1));//substring form 0 to j
long second = Long.parseLong(input.substring(j + 1, i + 1));//substring from j + 1 to i
if(second < first)
continue;
String last = "" + first + second;
System.out.println("first :"+first+" second :"+second);
if(last.length() == input.length()){
return false;
}
// firstTwo.add(first);
// firstTwo.add(second);
while(last.length() < input.length()){
long nxt = first + second;
last += nxt;
first = second;
second = nxt;
}
if(last.equals(input)){//Matched!
System.out.println("matched");
// dont go further return true
return true;
}
// firstTwo.clear();
}
}
return false;
}
Related
The longest increasing subsequence is the well known problem and I have a solution with the patience algorithm.
Problem is, my solution gives me the "Best longest increasing sequence" instead of the First longest increasing sequence that appears.
The difference is that some of the members of the sequence are larger numbers in the first(but the sequence length is exactly the same).
Getting the first sequence is turning out to be quite harder than expected, because having the best sequence doesn't easily translate into having the first sequence.
I've thought of doing my algorithm then finding the first sequence of length N, but not sure how to.
So, how would you find the First longest increasing subsequence from a sequence of random integers?
My code snippet:
public static void main (String[] args) throws java.lang.Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int inputInt;
int[] intArr;
try {
String input = br.readLine().trim();
inputInt = Integer.parseInt(input);
String inputArr = br.readLine().trim();
intArr = Arrays.stream(inputArr.split(" ")).mapToInt(Integer::parseInt).toArray();
} catch (NumberFormatException e) {
System.out.println("Could not parse integers.");
return;
}
if(inputInt != intArr.length) {
System.out.println("Invalid number of arguments.");
return;
}
ArrayList<ArrayList<Integer>> sequences = new ArrayList<ArrayList<Integer>>();
int sequenceCount = 1;
sequences.add(new ArrayList<Integer>());
sequences.get(0).add(0);
for(int i = 1; i < intArr.length; i++) {
for(int j = 0; j < sequenceCount; j++) {
if(intArr[i] <= intArr[sequences.get(j).get(sequences.get(j).size() - 1)]) {
sequences.get(j).remove(sequences.get(j).size() - 1);
sequences.get(j).add(i);
break;
} else if (j + 1 == sequenceCount) {
sequences.add(new ArrayList<Integer>(sequences.get(j)));
sequences.get(j + 1).add(i);
sequenceCount++;
break; //increasing sequenceCount causes infinite loop
} else if(intArr[i] < intArr[sequences.get(j + 1).get(sequences.get(j + 1).size() - 1)]) {
sequences.set(j+ 1, new ArrayList<Integer>(sequences.get(j)));
sequences.get(j+ 1).add(i);
break;
}
}
}
int bestSequenceLength = sequenceCount;
ArrayList<Integer> bestIndexes = new ArrayList<Integer>(sequences.get(bestSequenceLength - 1));
//build bestSequence, then after it I'm supposed to find the first one instead
int[] bestSequence = Arrays.stream(bestIndexes.toArray()).mapToInt(x -> intArr[(int) x]).toArray();
StringBuilder output = new StringBuilder("");
for(Integer x : bestSequence) {
output.append(x + " ");
}
System.out.println(output.toString().trim());
}
I'm storing indexes instead in preparation for having to access the original array again. Since it's easier to go from indexes to values than vice versa.
Example:
3 6 1 2 8
My code returns: 1 2 8
First sequence is: 3 6 8
Another Example:
1 5 2 3
My code correctly returns: 1 2 3
Basically, my code works as long as the first longest sequence is the same as the best longest sequence. But when you have a bunch of longest sequences of the same length, it grabs the best one not the first one.
Code is self-explanatory. (Have added comments, let me know if you need something extra).
public class Solution {
public static void main(String[] args) {
int[] arr = {3,6,1,2,8};
System.out.println(solve(arr).toString());
}
private static List<Integer> solve(int[] arr){
int[][] data = new int[arr.length][2];
int max_length = 0;
// first location for previous element index (for backtracing to print list) and second for longest series length for the element
for(int i=0;i<arr.length;++i){
data[i][0] = -1; //none should point to anything at first
data[i][1] = 1;
for(int j=i-1;j>=0;--j){
if(arr[i] > arr[j]){
if(data[i][1] <= data[j][1] + 1){ // <= instead of < because we are aiming for the first longest sequence
data[i][1] = data[j][1] + 1;
data[i][0] = j;
}
}
}
max_length = Math.max(max_length,data[i][1]);
}
List<Integer> ans = new ArrayList<>();
for(int i=0;i<arr.length;++i){
if(data[i][1] == max_length){
int curr = i;
while(curr != -1){
ans.add(arr[curr]);
curr = data[curr][0];
}
break;
}
}
Collections.reverse(ans);// since there were added in reverse order in the above while loop
return ans;
}
}
Output:
[3, 6, 8]
The Problem
Given a set of integers, find a subset of those integers which sum to 100,000,000.
Solution
I am attempting to build a tree containing all the combinations of the given set along with the sum. For example, if the given set looked like 0,1,2, I would build the following tree, checking the sum at each node:
{}
{} {0}
{} {1} {0} {0,1}
{} {2} {1} {1,2} {0} {2} {0,1} {0,1,2}
Since I keep both the array of integers at each node and the sum, I should only need the bottom (current) level of the tree in memory.
Issues
My current implementation will maintain the entire tree in memory and therefore uses way too much heap space.
How can I change my current implementation so that the GC will take care of my upper tree levels?
(At the moment I am just throwing a RuntimeException when I have found the target sum but this is obviously just for playing around)
public class RecursiveSolver {
static final int target = 100000000;
static final int[] set = new int[]{98374328, 234234123, 2341234, 123412344, etc...};
Tree initTree() {
return nextLevel(new Tree(null), 0);
}
Tree nextLevel(Tree currentLocation, int current) {
if (current == set.length) { return null; }
else if (currentLocation.sum == target) throw new RuntimeException(currentLocation.getText());
else {
currentLocation.left = nextLevel(currentLocation.copy(), current + 1);
Tree right = currentLocation.copy();
right.value = add(currentLocation.value, set[current]);
right.sum = currentLocation.sum + set[current];
currentLocation.right = nextLevel(right, current + 1);
return currentLocation;
}
}
int[] add(int[] array, int digit) {
if (array == null) {
return new int[]{digit};
}
int[] newValue = new int[array.length + 1];
for (int i = 0; i < array.length; i++) {
newValue[i] = array[i];
}
newValue[array.length] = digit;
return newValue;
}
public static void main(String[] args) {
RecursiveSolver rs = new RecursiveSolver();
Tree subsetTree = rs.initTree();
}
}
class Tree {
Tree left;
Tree right;
int[] value;
int sum;
Tree(int[] value) {
left = null;
right = null;
sum = 0;
this.value = value;
if (value != null) {
for (int i = 0; i < value.length; i++) sum += value[i];
}
}
Tree copy() {
return new Tree(this.value);
}
}
The time and space you need for building the tree here is absolutely nothing at all.
The reason is because, if you're given
A node of the tree
The depth of the node
The ordered array of input elements
you can simply compute its parent, left, and right children nodes using O(1) operations. And you have access to each of those things while you're traversing the tree, so you don't need anything else.
The problem is NP-complete.
If you really want to improve performance, then you have to forget about your tree implementation. You either have to just generate all the subsets and sum them up or to use dynamic programming.
The choice depends on the number of elements to sum and the sum you want to achieve. You know the sum it is 100,000,000, bruteforce exponential algorithm runs in O(2^n * n) time, so for number below 22 it makes sense.
In python you can achieve this with a simple:
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
You can significantly improve this complexity (sacrificing the memory) by using meet in the middle technique (read the wiki article). This will decrease it to O(2^(n/2)), which means that it will perform better than DP solution for n <~ 53
After thinking more about erip's comments, I realized he is correct - I shouldn't be using a tree to implement this algorithm.
Brute force usually is O(n*2^n) because there are n additions for 2^n subsets. Because I only do one addition per node, the solution I came up with is O(2^n) where n is the size of the given set. Also, this algorithm is only O(n) space complexity. Since the number of elements in the original set in my particular problem is small (around 25) O(2^n) complexity is not too much of a problem.
The dynamic solution to this problem is O(t*n) where t is the target sum and n is the number of elements. Because t is very large in my problem, the dynamic solution ends up with a very long runtime and a high memory usage.
This completes my particular solution in around 311 ms on my machine, which is a tremendous improvement over the dynamic programming solutions I have seen for this particular class of problem.
public class TailRecursiveSolver {
public static void main(String[] args) {
final long starttime = System.currentTimeMillis();
try {
step(new Subset(null, 0), 0);
}
catch (RuntimeException ex) {
System.out.println(ex.getMessage());
final long endtime = System.currentTimeMillis();
System.out.println(endtime - starttime);
}
}
static final int target = 100000000;
static final int[] set = new int[]{ . . . };
static void step(Subset current, int counter) {
if (current.sum == target) throw new RuntimeException(current.getText());
else if (counter == set.length) {}
else {
step(new Subset(add(current.subset, set[counter]), current.sum + set[counter]), counter + 1);
step(current, counter + 1);
}
}
static int[] add(int[] array, int digit) {
if (array == null) {
return new int[]{digit};
}
int[] newValue = new int[array.length + 1];
for (int i = 0; i < array.length; i++) {
newValue[i] = array[i];
}
newValue[array.length] = digit;
return newValue;
}
}
class Subset {
int[] subset;
int sum;
Subset(int[] subset, int sum) {
this.subset = subset;
this.sum = sum;
}
public String getText() {
String ret = "";
for (int i = 0; i < (subset == null ? 0 : subset.length); i++) {
ret += " + " + subset[i];
}
if (ret.startsWith(" ")) {
ret = ret.substring(3);
ret = ret + " = " + sum;
} else ret = "null";
return ret;
}
}
EDIT -
The above code still runs in O(n*2^n) time - since the add method runs in O(n) time. This following code will run in true O(2^n) time, and is MUCH more performant, completing in around 20 ms on my machine.
It is limited to sets less than 64 elements due to storing the current subset as the bits in a long.
public class SubsetSumSolver {
static boolean found = false;
static final int target = 100000000;
static final int[] set = new int[]{ . . . };
public static void main(String[] args) {
step(0,0,0);
}
static void step(long subset, int sum, int counter) {
if (sum == target) {
found = true;
System.out.println(getText(subset, sum));
}
else if (!found && counter != set.length) {
step(subset + (1 << counter), sum + set[counter], counter + 1);
step(subset, sum, counter + 1);
}
}
static String getText(long subset, int sum) {
String ret = "";
for (int i = 0; i < 64; i++) if((1 & (subset >> i)) == 1) ret += " + " + set[i];
if (ret.startsWith(" ")) ret = ret.substring(3) + " = " + sum;
else ret = "null";
return ret;
}
}
EDIT 2 -
Here is another version uses a meet in the middle attack, along with a little bit shifting in order to reduce the complexity from O(2^n) to O(2^(n/2)).
If you want to use this for sets with between 32 and 64 elements, you should change the int which represents the current subset in the step function to a long although performance will obviously drastically decrease as the set size increases. If you want to use this for a set with odd number of elements, you should add a 0 to the set to make it even numbered.
import java.util.ArrayList;
import java.util.List;
public class SubsetSumMiddleAttack {
static final int target = 100000000;
static final int[] set = new int[]{ ... };
static List<Subset> evens = new ArrayList<>();
static List<Subset> odds = new ArrayList<>();
static int[][] split(int[] superSet) {
int[][] ret = new int[2][superSet.length / 2];
for (int i = 0; i < superSet.length; i++) ret[i % 2][i / 2] = superSet[i];
return ret;
}
static void step(int[] superSet, List<Subset> accumulator, int subset, int sum, int counter) {
accumulator.add(new Subset(subset, sum));
if (counter != superSet.length) {
step(superSet, accumulator, subset + (1 << counter), sum + superSet[counter], counter + 1);
step(superSet, accumulator, subset, sum, counter + 1);
}
}
static void printSubset(Subset e, Subset o) {
String ret = "";
for (int i = 0; i < 32; i++) {
if (i % 2 == 0) {
if ((1 & (e.subset >> (i / 2))) == 1) ret += " + " + set[i];
}
else {
if ((1 & (o.subset >> (i / 2))) == 1) ret += " + " + set[i];
}
}
if (ret.startsWith(" ")) ret = ret.substring(3) + " = " + (e.sum + o.sum);
System.out.println(ret);
}
public static void main(String[] args) {
int[][] superSets = split(set);
step(superSets[0], evens, 0,0,0);
step(superSets[1], odds, 0,0,0);
for (Subset e : evens) {
for (Subset o : odds) {
if (e.sum + o.sum == target) printSubset(e, o);
}
}
}
}
class Subset {
int subset;
int sum;
Subset(int subset, int sum) {
this.subset = subset;
this.sum = sum;
}
}
My assignment for school is to implement a method that checks if a given ArrayList is part of the Fibonacci sequence.
The array must not be empty and must be bigger than 3.
I understood that I have to check if one number of the array and the next one are part of the Fibonacci sequence, however I have a lot of trouble with it since you're supposed to accept the array if it's any part of the sequence and not just from the start.
e.g.: 0 1 1 2 3 5 will be accepted as well as 2 3 5 8 13 21.
This is my code so far. I know it's very flawed but i really have no clue how to move on.
public class ArrayCheck {
/**
* Tests if the given array is a part of the Fibonacci sequence.
*
* #param arr array to be tested
* #return true if the elements are part of the fibonacci sequence
*/
public boolean isFibonacci(ArrayList<Integer> arr) {
//check if array exists
if(arr.size() == 0)
return false;
//check if array is bigger than 3
if (arr.size() < 3)
return false;
//check for the startsequence of 0,1,1
else if(arr.get(0) == 0 && arr.get(1) == 1 && arr.get(2) == 1)
return true;
//check every number in array
for(int i = 0; i < arr.size(); i++) {
//check if i >= 2 is fib
if(i >= 2) {
int fibn = i;
int nextfib = i + 1;
int fibnew = (fibn - 1) + (fibn - 2);
int fibnext = (nextfib - 1) + (nextfib - 2);
if (arr.get(i) != fibnew && arr.get(i + 1) != fibnext)
return false;
}
//check if the order is right
if(arr.get(i) > arr.get(i+1))
return false;
}
return true;
}
Any help is greatly appreciated!
Well, you have a few issues with your code. First of all, if you array is at least 3 items, you check if only the first three are the start of the Fibonacci sequence:
//check for the startsequence of 0,1,1
else if(arr.get(0)==0 && arr.get(1)==1 && arr.get(2)==1){
return true;
}
This is bad, as this mean 0 1 1 5 which is not part of the sequence will return true.
What you need to do is split this into two tasks:
Find the first relevant number in the sequence (i.e. if the array starts with 7, you know this isn't a part of the sequence; alternatively, if it starts with 8, you know you need to start checking from 8 onward).
Once you've found the "start", simply check that the rest of the array follows the Fibonacci rule. you'll need to manually verify the first two items.
public boolean isFibonacci(ArrayList<Integer> arr) {
if (arr.size() < 3){
return false;
}
/** find if the first element is part of the sequence: **/
int fib1 = 0;
int fib2 = 1;
while (fib1 < arr.get(0)) {
int tmp = fib1 + fib2;
fib1 = fib2;
fib2 = tmp;
}
if (fib1 != arr.get(0)) {
// first element is not part of Fibonacci sequence
return false;
}
if (fib2 != arr.get(1)) {
// the first two elements are not part of the Fibonacci sequence
return false;
}
/*** now simply verify that the rest of the elements uphold the rule:
each element is the sum of the two previous ones: **/
for(int i=2; i < arr.size(); i++) {
// make sure there are no negatives in the array:
if (arr.get(i) < 0)
return false;
if (arr.get(i) != (arr.get(i-1) + arr.get(i-2)))
return false;
}
//everything checks out okay - return true:
return true;
}
private boolean isFib(final List<Integer> li) {
//check if each int is the sum of the two prior ints
for (int i = 2; i < li.size(); i++) {
if (li.get(i) != li.get(i - 1) + li.get(i - 2)) {
return false;
}
}
//reverse the fibonacci sequence and check if we end up at the correct starting point (0, 1)
int i1 = li.get(0);
int i2 = li.get(1);
while (i1 > 0) {
final int tmp = i1;
i1 = i2 - i1;
i2 = tmp;
}
return i1 == 0 && i2 == 1;
}
I'd suggest a solution which abstracts Fibonacci sequence generator in a separate Iterator<Integer>, then uses it to check if provided list matches any part of the sequence.
Iterator is quite simple and straightforward:
public static class FiboIterator implements Iterator<Integer> {
#Override
public boolean hasNext() { return true; }
int i = -1, j = -1; // previous two items of Fibo sequence
#Override
public Integer next() {
int k = (i < 0) ? (j < 0 ? 0 : 1) : (i + j);
i = j;
j = k;
return k;
}
}
Main checking method:
public static boolean isFibo(List<Integer> seq) {
if (seq.size() < 3)
return false;
final Iterator<Integer> f = new FiboIterator();
int start = seq.get(0), k;
while ((k = f.next()) < start); // roll Fibo to match the starting item in input
if (start != k) // starting item doesn't match
return false;
if (start == 1 && seq.get(1) != 1) // special case: [1, 2, ...]
f.next();
for (int i = 1; i < seq.size(); i++) { // check if other items match
if (seq.get(i) != f.next())
return false;
}
return true;
}
And finally a few unit tests:
#Test
public void testFibo() {
assertTrue(isFibo(Arrays.asList(0, 1, 1, 2)));
assertTrue(isFibo(Arrays.asList(1, 1, 2, 3, 5)));
assertTrue(isFibo(Arrays.asList(1, 2, 3, 5, 8)));
assertTrue(isFibo(Arrays.asList(5, 8, 13, 21, 34)));
assertFalse(isFibo(Arrays.asList(1, 2, 0)));
assertFalse(isFibo(Arrays.asList(1, 0, 1)));
assertFalse(isFibo(Arrays.asList(5, 5, 10, 15)));
}
I'm having a difficult time with my program! For this method I have to check to see if all the numbers are distinct and I can't figure out for the life of me what I am doing wrong. I don't know if using an array is the best way to go. I must call the getDigit method.
for (int i = 0; i <= numDigits(number); i++) {
int digit = getDigit(number,i);
if (digit == getDigit(number,i)) {
return false;
}
}
return true;
You can first get each digit from the number and add them to a HashSet, then compare the size of HashSet with the number of digits present in the number
You can try this code:
public static void main(String[] args) {
int val = 123554;
Set<Integer> set = new HashSet<Integer>(); // HashSet contains only unique elements
int count = 0; // keeps track of number of digits encountered in the number
// code to get each digit from the number
while (val > 0) {
int tempVal = val % 10;
set.add(tempVal); // add each digit to the hash set
// you can have a boolean check like if(!set.add(tempVal)) return false; because add() returns false if the element is already present in the set.
val = val / 10;
count++;
}
if (count == set.size()) {
System.out.println("duplicate digit not present");
} else {
System.out.println("duplicate digit present");
}
}
Splitting Int into single digits:
Use something similar to this:
Code to print the numbers in the correct order:
int number; // = and int
LinkedList<Integer> stack = new LinkedList<Integer>();
while (number > 0) {
stack.push( number % 10 );
number = number / 10;
}
while (!stack.isEmpty()) {
print(stack.pop());
}
Source
Checking for Duplicates:
Again, something similar to this:
public static boolean duplicates (int [] x, int numElementsInX ) {
Set<Integer> set = new HashSet<Integer>();
for ( int i = 0; i < numElementsInX; ++i ) {
if ( set.contains( x[i])) {
return true;
}
else {
set.add(x[i]);
}
}
return false;
}
Source
Alternative
If you can split the array, an alternative could be to use:
int[] numbers = { 1, 5, 23, 2, 1, 6, 3, 1, 8, 12, 3 };
Arrays.sort(numbers);
for(int i = 1; i < numbers.length; i++) {
if(numbers[i] == numbers[i - 1]) {
System.out.println("Duplicate: " + numbers[i]);
}
}
i suppose that you want to compare for example the number 12345 with 23145, and prompt out a false, and if they are the same (digit by digit, prompt a true) , am i right?.
If you want to do this, you should make 2 arrays and you have to make sure to compare each position of both so you can compare digit by digit.
Hope it helps you
public boolean unique(int theNumber) {
String number = new Integer(theNumber).toString();
Set<Character> set = new LinkedHashSet<Character>();
for(char c:number.toCharArray()) {
set.add(Character.valueOf(c));
}
return number.length() == set.size();
}
I have an array of random length full of random integers. For the sake of simplicity, they are ordered from the highest to the lowest.
I also have a target random integer.
I need to get all the combinations which sum is greater or equal to the target without using unnecesary numbers. Given this example:
nums = [10, 6, 5, 3, 2, 1, 1]
target = 8
I want this output:
10 (10 is higher or equal to 8, so there's no need to sum it)
6+5
6+3
6+2
6+1+1
5+3
5+2+1
5+2+1 (Note that this result is different from the previous since there are 2 1s)
I've tried a lot of recursive strategies but I can't find a correct answer. No specific language is required, pseudocode is welcome.
EDIT: Posting code
private static boolean filtrar(final CopyOnWriteArrayList<Padre> padres) {
if (sum(padres) < TARGET) {
return false;
}
int i;
for (i = padres.size(); i >= 0; i--) {
if (!filtrar(copiaPadresSinElemento(padres, i-1))) {
break;
}
}
// Solución óptima, no se puede quitar nada.
if (i == padres.size()) {
print(padres);
}
return true;
}
private static int sum(final CopyOnWriteArrayList<Padre> padres) {
int i = 0;
for (final Padre padre : padres) {
i += padre.plazas;
}
return i;
}
private static void print(final CopyOnWriteArrayList<Padre> padres) {
final StringBuilder sb = new StringBuilder();
for (final Padre padre : padres) {
sb.append(padre);
sb.append(", ");
}
final String str = sb.toString();
System.out.println(str);
}
private static CopyOnWriteArrayList<Padre> copiaPadresSinElemento(
final CopyOnWriteArrayList<Padre> padres, final int i) {
final CopyOnWriteArrayList<Padre> copia = new CopyOnWriteArrayList<Padre>();
for (int e = 0; e < padres.size(); e++) {
if (e != i) {
copia.add(padres.get(e));
}
}
return copia;
}
Padre is a simple object which contains a name for each number. Padre.plazas is the number.
The array right now is [6,4,4,4,3,3,3], and the target is 8.
I think something like this would work:
function filter(array, target): Boolean{ //assumes array is sorted in descending order
if(sum(array) < target) return false;
for(i = array.length-1; i>=0; --i){
if(! filter(array.createCopyRemovingElementAt(i), target)) break;
}
if(i==array.length-1) print(array); // solution is "optimal": could not remove a single number
return true;
}
An inefficient solution : Complexity = O((2^n)*n)
for i = 0 to 2^size-of-array
do
sum = 0
for j = 0 to n-1
do
if(jth bit in i is 1)
then
sum+=array[j]
fi
done
if(sum>=target)
print the number i (uniquely identifies the set of numbers)
done