Better algorithm for finding solutions to "a + b = c + d" - algorithm

So lets abcd is a number between 1000 and 9999 and a,b,c,d are it's digits.
So find the number, where a+b=c+d. There is one solution down with four loops, but i need
a solution with three loops.
for (int a = 1; a <= 9; a++)
{
for (int b = 0; b <= 9; b++)
{
for (int c = 0; c <= 9; c++)
{
for (int d = 0; d <= 9; d++)
{
if ((a + b) == (c + d))
{
Console.WriteLine(" " + a + " " + b + " " + c + " " + d);
}
}
}
}
}

If someone asked you to solve the x + 1 == 2 equation, would you actually attempt to loop over all possible values of x to see which one fits? I hope not. You will probably figure out that the equation permits an immediate direct analytical solution x = 2 - 1 = 1.
The same logic applies to your case. Once you know a, b and c, your a + b == c + d equation permits a direct solution for d: d = a + b - c. There's no need to iterate over d just like there's no need to iterate over x in x + 1 == 2.

The first 3 loops establish values for a, b, and c. Knowing this and your equation just compute what d needs to be in order for your equation to hold true. Then check that the number computed for d is valid.
for (int a = 1; a <= 9; a++)
{
for (int b = 0; b <= 9; b++)
{
for (int c = 0; c <= 9; c++)
{
d = a + b - c;
if (d <= 9 && d >= 0)
{
Console.WriteLine(" " + a + " " + b + " " + c + " " + d);
}
}
}
}

What you have a special case of 4SUM that can be solved via one of the ways to quadratically solve 3SUM, making it O(N^2). Although it requires some use of data structures.
The first thing to note is since you are looking for A + B = C + D, What you really want to do is find a list of pairs of numbers that add up to some number S.
You can simply this by having a map/dict where the key is the sum and it maps to an list of pairs that equal that sum. The result is:
S = [(a,b),(c,d),(e,f),...] for a number of values of S
Which is equivalent to saying:
a + b = c + d = e + f = ... = S for a number of values of S
You then simply go through each sum and remove the ones where there is only a single element in the list.
I'm thinking you can then break go through the combinations of pairs obtaining things like a + b = c + d and c + d = e + f, at a cost of an additional O(N^2) as long as there are no duplicates due to limits on how many ways you can obtain a sum. Although, I might be wrong and it takes O(N^3) to list the solution in that form.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test
{
class Program
{
static void Main(string[] args)
{
var number = Enumerable.Range(1000, 9000);
var list = from y in number
let a = y / 1000
let b = (y - 1000 * a) / 100
let c = (y - 1000 * a - 100 * b) / 10
let d = (y - 1000 * a - 100 * b - 10 * c)
where a + b == c + d
select y;
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.Read();
}
}
}

String s1;
Set<String> s=new TreeSet();
for( int i=1;i<10;i++)
{
s1=null;
s1=""+i;
for(int j=0;j<10;j++)
{
String tempj=s1;
s1=s1+j;
for(int k=0;k<10;k++)
{
String tempk=s1;
s1=s1+k;
int temp=i+j-k;
s1=s1+temp;
if(temp<10)
s.add(s1);
s1=tempk;
}
s1=tempj;
}
}
for(String i:s )
System.out.println(i+);
----------------------------------------------------------------EDIT 1------------------
import java.util.*;
public class HelloWorld{
public static void main(String []args){
String happyNumber;
Set<String> numberSet=new TreeSet();
for( int i=1;i<10;i++)
{
happyNumber=null; //Every 1st loop will give a new number so old one has to be deleted
happyNumber=""+i; //Adding the number in 1st place (place value will be i*10000)
for(int j=0;j<10;j++) //Loop for putting nmber in 1000th place
{
String tempj=happyNumber; //taking happyNumber( only one digit fixed till now) into a temp variable to permutate on other places
happyNumber=happyNumber+j; //Attaching another number after this we have (AB)
for(int k=0;k<10;k++) //permutating with value of c and calculating d
{
String tempk=happyNumber;
happyNumber=happyNumber+k; //Attaching variable for 3rd place (c)
int temp=i+j-k; //calculating value of d
if(temp<10) //checking whether we have right value for d
{
happyNumber=happyNumber+temp;
numberSet.add(happyNumber);
}
happyNumber=tempk; //bringing number back to its previous state for more combination
}
happyNumber=tempj; //bringing number back to its previous state for more combination
}
}
for(String i:numberSet )
System.out.println(i);
}
}

Related

Algorithm to find how many times a string A needs to be stated such that it contains string B as substring

I haven't been able to come up with a bullet proof answer to this question. My solution fails few cases. I would appreciate some insights.
Question:
Given two strings A and B, return the number of times A needs to be stated such that it contains string B?
Example #1:
String A : abcd
String B : cdabcdab
Should return 3 because:
abcdabcdabcd ( A repeated 3 times)
cdabcdab ( B is contained in now)
Example #2:
String A = abcd
String B = d
should return 1 because B is already a substring of A.
Example #3:
String A = abcd
String B = cda
Should return 2 because:
abcdabcd
cda
Example #4:
String A = abcd
String B = cdb
Should return -1, it doesn't matter how many times we state A, there is no way we can produce B.
Few insights I have noticed:
Order of characters matter
A must contain at least all the
characters in B
Neither A or B needs to be a substring of the
other.
There must be an overlap between the end of one string and
the beginning of the other.
If |B| > 2|A| - 2 and B occurs in A^n, then A occurs in B. Count and remove all complete instances of A in B, and then the solution is this count plus the solution to the same problem with A's removed from B.
Otherwise, it is guaranteed that if B appears in A^n, it appears in A^3. Construct A^3 and find the first occurrence of B in it. Find and remove any complete instances of A appearing after the end of B's appearance in A^3. Return 3 minus the number of removed instances.
Examples:
f(abcd, cdabcdab)
|cdabcdab| > 2|abcd| - 2 since 8 > 2*4 - 2
^^^^
first instance of A in B; no more, so return 1 + f(cdab, abcd) = 3
f(cdab, abcd)
|cdab| < 2|abcd| - 2 since 4 < 2*4 - 2
abcdabcdabcd
^^^^
first instance of B in A; one instance of A after B, so return 3 - 1 = 2.
f(d, abcd)
|d| < 2|abcd| - 2, since 1 < 2*4 - 2
abcdabcdabcd
^
first instance of B in A; two instances of A after B, so return 3 - 2 = 1.
f(cda, abcd)
|cda| = 2|abcd| - 2 since 3 = 2*4 - 2
abcdabcdabcd
^^^
first instance of B in A; one instance of A after B, so return 3 - 1 = 2.
f(cdb, abcd)
|cbd| = 2|abcd| - 2 since 3 = 2*3 - 2
abcdabcdabcd
^ no instances of B in A; return -1.
Some minor optimizations include:
if |B| = 0, return 0.
if |B| = 1, use A^1 instead of A^3.
if |B| < |A| + 2, use A^2 instead of A^3.
One way to do it as like the code segment below. I noticed that no matter how many times we duplicate string A, this number (of times) can't be greater than length of string B. I hope this helps. Please note my answer runs in O(N^2) time. Not Ideal but any brute force solution should give you a good start towards the optimum/final solution.
string A = "abcd";
string B = "cda";
int i = 1;
string S = A;
while (i < B.Length)
{
S = S + A;
i++;
if(S.Contains(B))
break;
}
if(i==B.Length-1 && !S.Contains(B))
Console.WriteLine(-1); //not found
Console.WriteLine(i); //the solution
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a,b,s="";
cin>>a>>b;int count=0;
size_t f = a.find(b);
if(f==string::npos)
{
for(int i=0;i<b.length() && s.find(b)==string::npos;++i)
{
s.append(a);
count++;
}
}
else
{
cout<<1<<endl;
return 0;
}
if(s.find(b)!=string::npos)
cout<<count;
else
cout<<0<<endl;
return 0;
}
If A is longer than B then return 1 if B is in A.
if A is same length as B and they are equal return 1.
Look for the location in which B contains A, with a wrap around.
So A is abc and B is bca you will find that A is in B starting at [2]. Then start covering B with A starting with that location and count how many times you had to repeat A. Note that if covering fails, you need to keep searching for other possible places where A is in B.
it is guaranteed that if B appears in A^n, it appears in A^3.
So writing simple Java Code :
import java.io.*;
public class StringDemo {
public static void print(String x){
System.out.println(x);
}
public static void main(String args[]) {
String A = "abcd";
int alen = A.length();
String B = "cda";
int blen = B.length();
String C = A+A+A;
int op = -1;
if (C.indexOf(B) > -1 ){
op = 3;
C = C.substring(0,alen*2);
if (C.indexOf(B) > -1){
op = 2;
C = C.substring(0,alen);
if (C.indexOf(B) > -1){
op = 1;
}
}
}
print(Integer.toString(op));
}
}
There is a similar question I solved few days ago.
The Question :
Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1.
For example, with A = "abcd" and B = "abcdabcd".
Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times ("abcdabcd").
One probable solution from my side can be this:
public class test1 {
public static void main(String[] args) {
String a = " abcd";
String b = "abcdabcd";
System.out.println(fix(a,b));
}
public static int fix(String a,String b) {
StringBuffer sbr = new StringBuffer(a);
int c = 1 ;
//for( ; sbr.length() < b.length() ; c++ ) {sbr.append(a) ; }
while(sbr.length() < b.length() ) {
sbr.append(a);
c++ ;
}
String t = sbr.toString();
// if str1 not contains then we can concatenate and we must increase the count
if(!t.contains(b)) {
t += a ;
c++ ;
}
if(t.contains(b)) {
c++ ;
}
return c ;
}
}
The output will be 3 .abcdabcdabcd => 3 times abcd then abcdabcd will be a substring of it. That's why answer 3 is correct. If str1 has str2 the we increment the count by 1.
My solution is naive, but I think it works fine. If anyone found a flaw in this, please let me know.
private static int countRepeatOfString(StringBuffer concatenate, String a, String b) {
if (concatenate.length() == 0 || b.length() == 0) {
return -1;
}
int maxConcatenateCount;
/* For cases like:
String A - abcd (length=4) Longest possible would be:
String B - cdabcdab (length=8) abcdabcdabcd
Let r = the ratio of String B length to String A length
r + 2 is for taking care of case:
String A - abc
String B - c(abc)a
*/
if (a.length() <= b.length()) {
maxConcatenateCount = b.length() / a.length() + 2;
return countOccurrence(maxConcatenateCount, concatenate, a, b);
} else {
return countOccurrence(2, concatenate, a, b);
}
}
private static int countOccurrence(int maxConcatenateCount, StringBuffer concatenate, String a, String b) {
boolean found = false;
int currentConcatenateCount = 1;
int repeatCount = 1;
while (currentConcatenateCount <= maxConcatenateCount) {
int index = concatenate.indexOf(b, 0);
if (index != -1) {
found = true;
break;
}
concatenate.append(a);
currentConcatenateCount++;
repeatCount++;
}
if (found) {
return repeatCount;
} else {
return -1;
}
}
Taking the solution from #Patrick87
Here is the code:
public class ATimesToContainB {
public static void main(String args[]) {
System.out.println();
String a = "abcd";
String b = "cdabcdabcdabcdab";
System.out.println("Brute Force Multiply A :" + a + " n= " + atimesbBruteForce(a, b) + " to contain B " + b);
System.out.println("Optimized Multiply A :" + a + " n= " + atimesb(a, b) + " to contain B " + b);
System.out.println();
a = "abcd";
b = "cdabcdabcdabcdabab";
System.out.println("Brute Force Multiply A :" + a + " n= " + atimesbBruteForce(a, b) + " to contain B " + b);
System.out.println("Optimized Multiply A :" + a + " n= " + atimesb(a, b) + " to contain B " + b);
System.out.println();
a = "abcd";
b = "cdabcdab";
System.out.println("Brute Force Multiply A :" + a + " n= " + atimesbBruteForce(a, b) + " to contain B " + b);
System.out.println("Optimized Multiply A :" + a + " n= " + atimesb(a, b) + " to contain B " + b);
System.out.println();
a = "abcd";
b = "d";
System.out.println("Brute Force Multiply A :" + a + " n= " + atimesbBruteForce(a, b) + " to contain B " + b);
System.out.println("Optimized Multiply A :" + a + " n= " + atimesb(a, b) + " to contain B " + b);
System.out.println();
a = "abcd";
b = "cda";
System.out.println("Brute Force Multiply A :" + a + " n= " + atimesbBruteForce(a, b) + " to contain B " + b);
System.out.println("Optimized Multiply A :" + a + " n= " + atimesb(a, b) + " to contain B " + b);
System.out.println();
a = "abcd";
b = "cdb";
System.out.println("Brute Force Multiply A :" + a + " n= " + atimesbBruteForce(a, b) + " to contain B " + b);
System.out.println("Optimized Multiply A :" + a + " n= " + atimesb(a, b) + " to contain B " + b);
}
//O(n*m^2)
private static int atimesbBruteForce(String a, String b) {
int n = a.length();
int m = b.length();
String tempA = a;
if (tempA.contains(b))
return 1;
for (int i = 1; i < m; i++) { // O(m)
tempA = tempA + a;
if (tempA.contains(b)) //O(n*m); since temp A length could be max "m" times a length which is "n", for checking contains it take O(textLength); O(m*n)
return i + 1;
}
return Integer.MIN_VALUE;
}
//Idea take from above stack overflow
//O((m^2)/n) -> i hope its right
private static int atimesb(String a, String b) {
int n = a.length();
int m = b.length();
if (m == 0)
return 0;
if (m == 1)
return (a.contains(b) ? 1 : -1);
int count;
if (m > 2 * n - 2) {
count = countTimes(b, a); // O(m/n)
if (count > 0) {
return count + atimesb(a, removeByTimes(b, a)); // O(m)
} else
return count;
} else if (m < n + 2) {
a = a + a;
count = countTimes(a, b); // O(m)
if (count > 0) {
return 1 + count;
} else
return Integer.MIN_VALUE;
} else {
a = a + a + a;
count = countTimes(a, b); // O(m)
if (count > 0)
return 3 - count;
else return Integer.MIN_VALUE;
}
}
private static String removeByTimes(String b, String a) {
return b.replaceAll(a, "");
}
/**
* It will count how many times "toCount" is occur in "fromCount" if occures at all
*
* #param fromToCount
* #param toCount
* #return How many times, otherwise 0 if not occur
*/
private static int countTimes(String fromToCount, String toCount) {
int count = 0;
while (fromToCount.contains(toCount)) {
fromToCount = fromToCount.replaceFirst(toCount, "");
count++;
}
return count;
}
}
Here is my solution in Python2 for the same. I followed mathematical way of solving the expression
def google(a,b):
x=(len(b)/len(a))+1
print x
google("abcd","cda")

FInd all lists of 4 positive integers whose sum is 100

I'd like to generate a list of all possible lists of 4 positive integers whose sum equals 100, exactly. (The summands do not need to be unique.)
Possible example snippet:
[
// Using (1+1+1+97)
[1,1,1,97],
[1,1,97,1],
[1,97,1,1],
[97,1,1,1],
// Using (2+1+1+96)
[2,1,1,96],
[2,1,96,1],
[2,96,1,1],
[96,2,1,1],
[1,2,1,96],
[1,2,96,1],
[1,96,2,1],
[96,1,2,1],
[1,1,2,96],
[1,1,96,2],
[1,96,1,2],
[96,1,1,2],
// Using (2+2+1+95), etc...
]
What's an efficient way of doing this? (Pseudo-code or advice is fine.)
Here's a generic solution for any number of parts:
// create(100, 4) returns the 156849 solutions
Iterable<List<int>> create(int max, int parts) sync* {
assert(max >= parts);
if (parts == 1) {
yield [max];
} else {
for (int i = max - parts + 1; i > 0; i--) {
yield* create(max - i, parts - 1).map((e) => e.toList()..add(i));
}
}
}
And a more optimized solution for 4 numbers:
// create(100) returns the 156849 solutions
Iterable<List<int>> create(int max) sync* {
for (int a = 1; a <= max - 3; a++) { // -3 because b/c/d are >= 1
for (int b = 1; b <= max - a; b++) {
for (int c = 1; c <= max - a - b - 1; c++) { // -1 because d is >=1
yield [a, b, c, max - a - b - c];
}
}
}
}
I think it is best to start with a solution and then change the solution to other valid solutions. I assume 0 is not a valid number.
Lets start at [97,1,1,1]
then we substract one from 97, leaving 96.
we have [96,1,1,1] leaving 1. So we have a question that gives us the partial answer:
"generate a list of all possible lists of 3 positive integers whose sum equals 4"
then we substract one from 96,
"generate a list of all possible lists of 3 positive integers whose sum equals 5"
then we substract one from 95,
"generate a list of all possible lists of 3 positive integers whose sum equals 6"
etc. etc.
because the bunch of questions really looks much like the original question we can re-do the trick to go from 3 places to 2 places.
[2,1,1] (leaving 1) => "generate a list of all possible lists of 2 positive integers whose sum equals 3" which is easy to write.
Now you can simply write a nice recursive formula.
Iterative and recursive solutions:
(Try it on DartPad
void main() {
List<List<int>> resultList1 = <List<int>>[];
for(int i1 = 1; i1 < 98; i1++) {
for(int i2 = 1; (i1 + i2) < 99; i2++) {
for(int i3 = 1; (i1 + i2 + i3) < 100; i3++) {
for(int i4 = 1; (i1 + i2 + i3 + i4) <= 100; i4++) {
if((i1 + i2 + i3 +i4) == 100) {
resultList1.add([i1, i2, i3, i4]);
}
}
}
}
}
// print(resultList1);
print(resultList1.length);
final int elementCount = 4;
final int target = 100;
final List<List<int>> resultList2 = <List<int>>[];
sum(elementCount, target, resultList2, [0, 0, 0, 0], 0);
// print(result);
print(resultList2.length);
}
void sum(int elementCount, int target, List<List<int>> result, List<int> values,
int curPos) {
for (int i = values[curPos] + 1; i <= target - curPos; i++) {
// debugging only
// if(curPos == 0) {
// print(i);
// }
// end debugging only
values[curPos] = i;
if (curPos == elementCount - 1) {
if (values.reduce((int a, int b) => a + b) == 100) {
// print(values);
result.add(values.toList());
}
} else {
sum(elementCount, target, result, values, curPos + 1);
}
for(int j = curPos + 1; j < values.length; j++) {
values[j] = 0;
}
}
}
The result contains 156849 elements from [1,1,1,97] to [97,1,1,1].
The recursive version supports variable number of elements and variable sum target value. For example by calling it like:
final int elementCount = 3;
final int target = 50;
final List<List<int>> resultList2 = <List<int>>[];
sum(elementCount, target, resultList2, [0, 0, 0], 0);
I think the most straightforward way is to use 3 loops.
resultList = []
for a from 1 to 97:
for b from 1 to 97:
for c from 1 to 97:
d = 100-a-b-c
if d > 0:
resultList.append([a,b,c,d])
recursive approach:
MakeSum(Sum, NItems, ResultList)
if NItems = 1
output ResultList + [Sum]
else
for i = 1 to Sum - NItems + 1
MakeSum(Sum - i, NItems - 1, ResultList + [i])
Here is a simple solution in Python that produces all possible results in lexicographic order:
resultList = []
for a in xrange(1,98):
for b in xrange(1,98):
for c in xrange(1,98):
d = 100 - a - b - c
if d > 0 and a <= b <= c <= d:
resultList.append([a,b,c,d])
The result list has 7153 entries, beginning with [1,1,1,97] and ending with [25,25,25,25]. You can run the program at http://ideone.com/8m7b1h.

Project Euler 31: Why does this solution work?

I have been studying various solution to Project Euler question #31:
In England the currency is made up of pound, £, and pence, p, and
there are eight coins in general circulation: 1p, 2p, 5p, 10p, 20p,
50p, £1 (100p) and £2 (200p).
It is possible to make £2 in the following way: 1x£1 + 1x50p + 2x20p + 1x5p + 1x2p + 3x1p
How many different ways can £2 be made using any number of coins?
I am confused why this particular brute force solution works (source):
int target = 200;
int ways = 0;
for (int a = target; a >= 0; a -= 200) {
for (int b = a; b >= 0; b -= 100) {
for (int c = b; c >= 0; c -= 50) {
for (int d = c; d >= 0; d -= 20) {
for (int e = d; e >= 0; e -= 10) {
for (int f = e; f >= 0; f -= 5) {
for (int g = f; g >= 0; g -= 2) {
ways++;
}
}
}
}
}
}
}
Based on this solution I would expect there to be one more nested for-loop at the innermost level that is decrementing by 1, for coins of 1p value.
For example, when do we count the scenario where 200p is made up of only 1p coins?
As it stands currently, the code leads to the correct answer. But if an additional for-loop was added then it would seem the answer should be much bigger. What am I missing?
Because the for-loops count up ways to make a number <= 200, assuming the remainder is made up of 1p coins. For example, consider the first iteration, where a = b = c = d = e = f = g = 200, this is exactly the case you asked about explicitly, where 200p is made of all 1's.
For any given combination of 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p) coins that sum up to £2 or less there's precisely one number of 1p coins that would make up an even £2. Hence, you don't need another loop to iterate the number of 1p coins.

how do I perform mathematical functions that may exceed LONG_MAX

how do I perform ( A div B ) mod C where I am calculating A in one function,B in another function,and C is say ( 10 pow 9 plus 7 ) but both A and B may be greater than C,or INT_MAX
if the only problem is the size of the numbers you can use long. if the number may be larger then long.MAX_VALUE then you need some function to calculate using strings, or use two or more long types, and make your own functions. for example, the plus function will get two long types, check if the sum of them is smaller then one of them(meaning they went over the MAX_SIZE), then return an array of long, containing to numbers, one for the carry bit, and one for the sum.
here is an example in c#, but it's easy to translate it to c++
public static string sum(long a, long b)
{
string sum;
if (a + b > a && a + b > b)
{
sum = (a + b).ToString();
}
else
{
string aStr = a.ToString();
string bStr = b.ToString();
if (bStr.Length > aStr.Length)
{
string tmp = aStr;
aStr = bStr;
bStr = tmp;
}
sum = new string('0', aStr.Length + bStr.Length);
char[] arr = sum.ToCharArray();
for (int i = 0; i < bStr.Length; i++)
{
int loc = sum.Length - 1 - i;
arr[loc] += (char)(aStr[aStr.Length - 1 - i] + bStr[bStr.Length - 1 - i] - '0' * 2);
if (arr[loc] > '9')
{
arr[loc - 1] = '1';
arr[loc] = (char)(arr[loc] - '9' - 1);
}
}
for (int i = bStr.Length ; i < aStr.Length; i++)
{
int loc = sum.Length - 1 - i;
arr[loc] += (char)(aStr[aStr.Length - 1 - i] - '0');
if (arr[loc] > '9')
{
arr[loc - 1] = '1';
arr[loc] = (char)(arr[loc] - '9' - 1);
}
}
sum = new string(arr);
}
return sum;
}
}

Find all the quadruples [a, b, c, d] where a^3 + b^3 = c^3 + d^3 when 1 <= a, b, c or d <= 10000 [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Looking for an algorithm or some coding hints to find the solutions for
a^3 + b^3 = c^3 + d^3, where a, b, c and d all are in the range [1 .. 10000]
It's an interview question.
I'm thinking priority queues to at least iterate for a and b values. Some hint will be great, will try to work through from there.
Using a hash map to store the (cube,(a,b)), you can iterate all possible pairs of integers, and output a solution once you have found that the required sum of cubes is already in the map.
pseudo code:
map <- empty hash_map<int,list<pair<int,int>>>
for each a in range(0,10^5):
for each b in range(a,10^5): //making sure each pair repeats only once
cube <- a^3 + b^3
if map.containsKey(cube):
for each element e in map.get(cube):
output e.first(), e.last(), a, b //one solution
else:
map.put(cube,new list<pair<int,int>>)
//for both cases, add the just found pair to the relevant list
map.get(cube).add(cube,new pair(a,b))
This solution is O(n^2) space(1) and O(n^2 + OUTPUT) time on average, where OUTPUT is the size of the output.
EDIT:
Required space is actually O(n^2 logn), where n is the range (10^5), because to represent 10^5 integers you need ceil(log_2(10^15)) = 50 bits. So, you actually need something like 500,000,000,000 bits (+ overhead for map and list) which is ~58.2 GB (+ overhead).
Since for most machines it is a bit too much - you might want to consider storing the data on disk, or if you have 64bits machine - just store in into "memory" and let the OS and virtual memory system do this as best as it can.
(1) As the edit clarifies, it is actually O(n^2log(n)) space, however if we take each integer storage as O(1) (which is usually the case) we get O(n^2) space. Same principle will apply for the time complexity, obviously.
Using a priority queue is almost certainly the simplest solution, and also the most practical one, since it's O(n) storage (with a log factor if you require bignums). Any solution which involves computing all possible sums and putting them in a map will require O(n^2) storage, which soon becomes impractical.
My naive, non-optimized implementation using a priority queue is O(n^2 log(n)) time. Even so, it took less than five seconds for n = 10000 and about 750 seconds for n = 100000, using a couple of megabytes of storage. It certainly could be improved.
The basic idea, as per your comment, is to initialize a priority queue with pairs (a, a+1) for a in the range [1, N), and then repeatedly increment the second value of the smallest (by sum of cubes) tuple until it reaches N. If at any time the smallest two elements in the queue are equal, you have a solution. (I could paste the code, but you only asked for a hint.)
Using Hashmap (O(n^2) solution):
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static java.lang.Math.pow;
/**
* Created by Anup on 10-10-2016.
*/
class Pair {
int a;
int b;
Pair(int x, int y) {
a = x;
b = y;
}
}
public class FindCubePair {
public static void main(String[] args) {
HashMap<Long, ArrayList<Pair>> hashMap = new HashMap<>();
int n = 100000;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
long sum = (long) (pow(i, 3) + pow(j, 3));
if(hashMap.containsKey(sum)) {
List<Pair> list = hashMap.get(sum);
for(Pair p : list) {
System.out.println(i + " " + j + " " + p.a + " " + p.b);
}
} else {
ArrayList<Pair> list = new ArrayList<>();
hashMap.put(sum, list);
}
hashMap.get(sum).add(new Pair(i, j));
}
}
}
}
Unfortunately, the value of integers printed does not even reach 1000 on my computer due to resource limitation.
A quicker than trivial solution is as follows: You calculate all values that a^3 + b^3 can have, and store all possible values of a and b with it. This is done by looping through a and b, storing the results (a^3 + b^3) in a binary tree and having a list of values (a's and b's) associated to each result.
After this step, you need to traverse the list and for each value, choose every possible assignment for a,b,c,d.
I think this solution takes O(n^2 log n) time and O(n^2) space, but i might be missing something.
int Search(){
int MAX = 10000000;
for(int a = 0; a < MAX; a++){
int a3 = a * a * a;
if(a3 > MAX) break;
for(int b = a; b < MAX; b ++){
int b3 = b * b * b;
if(a3 + b3 > MAX)break;
for(int c = 0; c < a; c++){
int c3 = c*c*c;
int m = a3 - c3;
int d = b+1;
while(true){
int d3 = d * d * d;
if(d3-b3 <= m){
if((d3 - b3) == m){
count++;
PUSH_Modified(a3, b3, c3, b3, a, b, c, d);
}
d++;
continue;
}
else
break;
}
}
}
}
return 0;
}
Let's assume a solution:
a=A, b=B, c=C, and d=D.
Given any solution we can generate another 3 solutions
abcd
ABCD
ABDC
BACD
BADC
Actually, if A=B, or C=D, then we might only have 1 or 2 further solutions.
We can choose the solutions we look for first by ordering A <= B and C <= D. This will reduce the search space. We can generate the missed solutions from the found ones.
There will always be at least one solution, where A=C and B=D. What we're looking for is when A>C and B<D. This comes from the ordering: C can't be greater than A because, as we've chosen to only look at solutions where D>C, the cube sum would be too big.
We can calculate A^3 + B^3, put it in a map as the key, with a vector of pairs A,B as the value.
There will be (n^2)/2 values.
If there are already values in the vector they will all have lower A and they are the solutions we're looking for. We can output them immediately, along with their permutations.
I'm not sure about complexity.
One Solution - using concept of finding 2 sum in a sorted array. This is O(n3)
public static void pairSum() {
int SZ = 100;
long[] powArray = new long[SZ];
for(int i = 0; i< SZ; i++){
int v = i+1;
powArray[i] = v*v*v;
}
int countPairs = 0;
int N1 = 0, N2 = SZ-1, N3, N4;
while(N2 > 0) {
N1=0;
while(N2-N1 > 2) {
long ts = powArray[N1] + powArray[N2];
N3 = N1+1; N4 = N2-1;
while(N4 > N3) {
if(powArray[N4]+powArray[N3] < ts) {
N3++;
}else if(powArray[N4]+powArray[N3] > ts) {
N4--;
}else{
//System.out.println((N1+1)+" "+(N2+1)+" "+(N3+1)+" "+(N4+1)+" CUBE "+ts);
countPairs++;
break;
}
}
N1++;
}
N2--;
}
System.out.println("quadruplet pair count:"+countPairs);
}
Logic :
a^3 + b^3 = c^3 + d^3
Then, a^3+b^3-c*3-d^3 = 0
Try to solve this equation by putting all combination of values for a,b,c and d in range of [0 , 10^5].
If equation is solved print the values of a,b,c and d
public static void main(String[] args) {
//find all solutions of a^3 + b^3 = c^3 + d^3
double power = 3;
long counter = 0; // to count the number of solution sets obtained
int limit = 100000; // range from 0 to limit
//looping through every combination of a,b,c and d
for(int a = 0;a<=limit;a++)
{
for(int b = 0;b<=limit;b++)
{
for(int c = 0;c<=limit;c++)
{
for(int d = 0;d<=limit;d++)
{
// logic used : a^3 + b^3 = c^3 + d^3 can be written as a^3 + b^3 - c^3 - d^3 = 0
long result = (long)(Math.pow(a,power ) + Math.pow(b,power ) - Math.pow(c,power ) - Math.pow(d,power ));
if(result == 0 )
{
counter++; // to count the number of solutions
//printing the solution
System.out.println( "a = "+ a + " b = " + b + " c = " + c + " d = " + d);
}
}
}
}
}
//just to understand the change in number of solutions as limit and power changes
System.out.println("Number of Solutions =" + counter);
}
Starting with the brute force approach, its pretty obvious it will O(n^4) time to execute.
If space is not a constraint, we can go for combination of list and maps.
The code is self-explanatory, we are using a nested list to keep track of all entries for a particular sum (key in map).
The time complexity is thus reduced from O(n^4) to O(n^2)
public void printAllCubes() {
int n = 50;
Map<Integer, ArrayList<ArrayList>> resMap = new HashMap<Integer, ArrayList<ArrayList>>();
ArrayList pairs = new ArrayList<Integer>();
ArrayList allPairsList = new ArrayList<ArrayList>();
for (int c = 1; c < n; c++) {
for (int d = 1; d < n; d++) {
int res = (int) (Math.pow(c, 3) + Math.pow(d, 3));
pairs.add(c);
pairs.add(d);
if (resMap.get(res) == null) {
allPairsList = new ArrayList<ArrayList>();
} else {
allPairsList = resMap.get(res);
}
allPairsList.add(pairs);
resMap.put(res, allPairsList);
pairs = new ArrayList<Integer>();
}
}
for (int a = 1; a < n; a++) {
for (int b = 1; b < n; b++) {
int result = (int) (Math.pow(a, 3) + Math.pow(b, 3));
ArrayList<ArrayList> pairList = resMap.get(result);
for (List p : pairList) {
System.out.print(a + " " + b + " ");
for (Object num : p)
System.out.print(num + " ");
System.out.println();
}
}
}
}

Resources