Recursive find order of square sums with given length

Viewed 782

Write function that, given an integer number N, returns array of integers 1..N arranged in a way, so sum of each 2 consecutive numbers is a square.

Solution is valid if and only if following two criterias are met:

Each number in range 1..N is used once and only once.

Sum of each 2 consecutive numbers is a perfect square(root square).

the result is a list of 1-n numbers in a specific order according to the rules above!!!

Example For N=15 solution could look like this:

[ 9, 7, 2, 14, 11, 5, 4, 12, 13, 3, 6, 10, 15, 1, 8 ]

check-

   16    16     16     16     16     16     16
   /+\   /+\    /+\    /+\    /+\    /+\    /+\
[ 9, 7, 2, 14, 11, 5, 4, 12, 13, 3, 6, 10, 15, 1, 8 ]
      \+/    \+/    \+/    \+/    \+/    \+/    \+/
       9     25      9     25      9     25      9


9 = 3*3
16 = 4*4
25 = 5*5

length of the returned list is n=15 and uses numbers from 1-n(15)

If there is no solution, return null For example if N=5, then numbers 1,2,3,4,5 cannot be put into square sums row: 1+3=4, 4+5=9, but 2 has no pairs and cannot link [1,3] and [4,5].

solution list return must be using numbers up to n and the length must be equal to n

my solution is using recursive method, here is my attempts:

import java.util.*;

public class SquareSums {
   public static List<Integer> gg= new ArrayList<Integer>() ;

    public static List<Integer> buildUpTo(int n) {
        int checkCurrent=1,firstInList=1;
        while(checkCurrent<=n+1){
          boolean[] flag= new boolean[n+1];
          List<Integer> l= new ArrayList<Integer>();
          l=checker(n,checkCurrent,l,1,flag,firstInList, true);//n, prev, list, current, flag
          checkCurrent++;
          if(l.size()==n) {System.out.println("true "+ n);return l;}
        }
         return null;
}
  public static List<Integer> checker(int num, int current,List<Integer> l,int prev, boolean[] flag,int k, boolean one){
      if(l.size()==num) {return l;}
      else if(prev>num+1 || current>num) {return l;}
      if(one) {
          flag[current]=true;
          l.add(current);print(l);
          l=checker(num,1,l,current,flag,1,false);
      }
          flag[prev]=true;
          System.out.println("check if square root: "+" num1: "+prev+ " num2: "+current+" sum is: "+(prev+current)+" sqrt: "+Math.sqrt(prev+current)+ " sqrt int: "+Math.floor(Math.sqrt(prev+current)));

          if(current<flag.length &&!flag[current] && Math.sqrt(prev+current)==Math.floor(Math.sqrt(prev+current))) {
            l.add(current);print(l);
            l=checker(num,1,l,current,flag,1,false);
          }
          else {
              print(l);
              l=checker(num,k++,l,prev,flag,k,false); 
          }
    return l;
  }
  
  public static void main(String[] args) {
      List<Integer> l= buildUpTo(15);
      print(l);
      }
  static void print(List<Integer> l) {
      System.out.println(" -------------------- ");
      for(int i=0;i<l.size();i++) {
          System.out.println(l.get(i));
      }
      System.out.println(" --------------------- ");
      System.out.println(" ");
      System.out.println(" ");


  }
  }

although I get true it fails because of the following: enter image description here

how can I solve/fix the code in order for It to work properly(using a recursive method&no streams?)?

here is the testing code:

import org.junit.Test;
import org.junit.runners.JUnit4;
import java.util.List;

public class Tests {
    
    @Test
    public void sampleTests() {
        
        List.of(5,15,16,23,37).forEach(Check::isGood); 
    }
}

EDIT:

then with the help of the code solution posted down below I edited my code a bit to this but it still doesn't work as it should.

public class SquareSums {
   public static List<Integer> gg= new ArrayList<Integer>() ;

    public static List<Integer> buildUpTo(int n) {
        int checkCurrent=1;
        while(checkCurrent<=n+1){
          List<Integer> l=checker(n,checkCurrent,new ArrayList<Integer>(),1,new boolean[n+1],1);//n, prev, list, current, flag
          checkCurrent++;
          if(l.size()==n) {System.out.println("true "+ n);return l;}
        }
         return gg;
         
}
  static boolean checkPerfectSquare(double x)
  {
      double sq = Math.sqrt(x);
      return ((sq - Math.floor(sq)) == 0);
  }
  public static List<Integer> checker(int num, int current,List<Integer> l,int prev, boolean[] flag,int k){
      if(l.size()==num) {return l;}
      else if(prev>num+1 || current>num) {return l;}
      if(l.size()==0) {
          flag[current]=true;
          l.add(current);System.out.println(l);
          l=checker(num,1,l,current,flag,1);
      }
          flag[prev]=true;
          if(current<flag.length &&!flag[current] && checkPerfectSquare(prev+current)) {
            l.add(current);System.out.println(l);
            l=checker(num,1,l,current,flag,1);
            l.remove(l.size()-1);
            flag[l.size()-1]=false;
          }
          else {
              System.out.println(l);
              l=checker(num,k++,l,prev,flag,k); 
          }
    return l;
  }
  
  public static void main(String[] args) {
      List<Integer> l= buildUpTo(15);
      System.out.println("\n"+"Answer is: ");
      System.out.println(" -------------------- ");
      System.out.println(l);
      System.out.println(" -------------------- ");

      }
  }

i ran through the code and when I run it on example n=15 which is true, its suppose to return a list which starts with 9, on mine on the debugger/printing on 9 it prints

[9, 7, 2, 14, 11, 5, 4, 12, 13, 3, **1, 8**]

and the expected actual result is:(not my code, the real solution when n=15)

[9, 7, 2, 14, 11, 5, 4, 12, 13, 3, **6, 10, 15, 1, 8**]

if we look closely we can see where my code went wrong. it seems that i need to add something to the recursion which goes back to try every option. how can i do so?

2 Answers

I have implemented code that can give you the sequence of consecutive sum squares to a particularly given range.

So you can modify it as per your requirement.

  public static void main(String[] args) {
        //n -> 0 will be starting point
        // size-> 15 size of sequence
        //range-> range for which you want to find. Example value should include between 1 to 30
        //check-> so that now value should be repeated so

        //if you want to repeat value just remove boolean flag it will work and put all if else into one code
        getvalue(0,15, new ArrayList<>(),20,new boolean[20]);
    }
    static void getvalue(int n, int size, ArrayList<Integer> ar, int range, boolean check[]) {
        if(n==size)
        {
            System.out.println(ar);
            return;
        }
        for (int i = 1; i < range; i++) {
            if (ar.size() == 0) {
                ar.add(i);
                check[i] = true;
                getvalue(n+1,size, ar,range, check);
                check[i] = false;
            }
            else if(check[i]==false)
            {
                int val=ar.get(ar.size()-1);
                if(checkPerfectSquare(val+i))
                {
                    check[i]=true;
                    ar.add(i);
                    getvalue(n+1,size, ar,range, check);
                    ar.remove(ar.size()-1);
                    check[i]=false;
                }
            }
        }
    }
    static boolean checkPerfectSquare(double x)
    {
        double sq = Math.sqrt(x);
        return ((sq - Math.floor(sq)) == 0);
    }

You can also check here-> https://github.com/murari99732/solutionleetcode-adventofcode/blob/master/PracticeAlgo/src/ConsecutiveSquare.java

This question can be rephrased as:

  1. finding the maximum sequence of the integers (1..N) that Sum of each 2 consecutive numbers is a perfect square(root square).
  2. If exists, the longest sequence is the size of array itself, which means every integer is presented in the result. If the longest is not the size of the array itself, return empty.

And another observation is: if the sequence exists, there must be a pair of results, because if result [0..n-1] is the result, then the reverse sequence [n-1 ..0] is also a result. for example:

[9, 7, 2, 14, 11, 5, 4, 12, 13, 3, 6, 10, 15, 1, 8]

and

[8, 1, 15, 10, 6, 3, 13, 12, 4, 5, 11, 14, 2, 7, 9]

both are correct answers.

Now finding the maximum sequence of the integers (1..N) that Sum of each 2 consecutive numbers is a perfect square(root square) sounds quite familiar with other maximum sequence algorithm questions. And DFS (Depth First Search) can be used for this question if you take 1 to n as a graph. (or you can call it Backtracking algorithm)

murari99732 has provided a solution using DFS, but just one minor issue when arr is 0

if (ar.size() == 0) {
            ar.add(i);
            check[i] = true;
            getvalue(n+1,size, ar,range, check);
            check[i] = false;
        }

the item should be reset after visited, and code should be:

   if (ar.size() == 0) {
                ar.add(i);
                check[i] = true;
                getvalue(n+1,size, ar,range, check);
                ar.remove(ar.size()-1);
                check[i] = false;
            }

And here is my complete code using DFS:

import java.util.ArrayList;
import java.util.List;

public class Test {


    private boolean checkPerfectSquare(double x)
    {
        double sq = Math.sqrt(x);
        return ((sq - Math.floor(sq)) == 0);
    }

    private void solution(int current, int size, List<Integer> ar, boolean check[]){

        if(current==size)
        {
            System.out.println(ar);
            return;
        }
        for (int i = 1; i <=size; i++) {
            if (ar.size() == 0) {
                check[i] = true;
                ar.add(i);
                solution(current+1,size, ar, check);
                ar.remove(ar.size()-1);
                check[i] = false;
            }
            else if(check[i]==false)
            {
                int val=ar.get(ar.size()-1);
                if(checkPerfectSquare(val+i))
                {
                    check[i]=true;
                    ar.add(i);
                    solution(current+1,size, ar, check);
                    ar.remove(ar.size()-1);
                    check[i]=false;
                }
            }
        }
    }

    public static void main(String[] args){

        Test test = new Test();

        test.solution(0,15, new ArrayList<>(),new boolean[16]);

    }
}
Related