Finding two specific numbers in huge arrays - java-7

I'm currently trying to solve an algorithm problem and due to being new to programming I feel like I won't be able to figure it out without some knowledge first. My intention is not to receive the answer to the problem but recommendations to process huge arrays in Java.
The problem is: you receive a number (3 > n < 200.000) and then receive a sorted array of numbers that has n length and then you receive another number (n2) (all the numbers can be hold by an int).
You have to find two numbers in the array that their sum will make n2-n.
You will always have a right answer and will always be two numbers.
Per example:
3
1 2 3
3
The answer would be 1 and 2 because 6 - 3 = 3;
My code works but it exceeds time and memory consumption. So I'm looking for someone to tell better ways to find those numbers than can also be applicable to improve my algorithm practices.
What I've done so far is to sum all the numbers in the array and obtain n2 - n; then create two indexes, the first 0 and the second (n2 - n) - 1; Then loop through while the first index is less than the second index. During the loop, performing a binary search of the first index and of the second index. If the binary search finds both numbers then return them as the answer.
public static BufferedReader br;
public static int numHechizos;
public static String line;
public static String[] split;
public static int damage;
public static int[] hechizos;
public static void main(String[] args) throws IOException {
br = new BufferedReader(new InputStreamReader(System.in));
numHechizos = Integer.parseInt(br.readLine());
while (numHechizos != 0){
caso(numHechizos);
numHechizos = Integer.parseInt(br.readLine());
}
}
public static void caso(int numHechizos) throws IOException {
line = br.readLine();
split = line.split(" ");
damage = Integer.parseInt(br.readLine());
int sum = 0;
hechizos = new int[numHechizos];
for (int i = 0; i < numHechizos; i++) {
int num = Integer.parseInt(split[i]);
hechizos[i] = num;
sum += num;
}
int find = sum - damage;
int n1 = 1; int n2 = find - 1;
while (n1 < n2){
int bn1 = Arrays.binarySearch(hechizos, n1);
int bn2 = Arrays.binarySearch(hechizos, n2);
if (bn1 > -1 && bn2 > -1){
System.out.println(n1 + " " + n2);
break;
}
n1++;
n2--;
}
System.gc();
}

Related

Algorithm for moving between permutations by swapping with first integer

I was asked an interesting interview question today. Suppose you have a permutation of the first n integers A (e.g. 13425) and another permutation B (e.g. 43125). We must move from the first permutation to the second, only by swapping values at indices 1 to n-1 with the value at index 0.
In other words, we can swap indices 0 and 1 in the sequence 13425 to yield 31425. But we cannot swap indices 2 and 3 in the sequence 13425 to yield 13245.
In the end, after these swaps we must come to permutation B. Can anyone come up with an algorithm with a better runtime than O(n^2)?
yes, there is exists O(N) solution, here is java implementation:
private static void swap(int[] idx, char[] c, int i) {
idx[c[i]-'0'] = 0;
idx[c[0]-'0'] = i;
char tc = c[0];
c[0] = c[i];
c[i] = tc;
}
public static void permutation(final String from, final String to) {
final int[] idx = new int[10];
final char[] c1 = from.toCharArray();
final char[] c2 = to.toCharArray();
for (int i = 0; i < c1.length; i++) {
idx[c1[i] - '0'] = i;
}
for (int i=(c1.length-1); i>=0; i--) {
if (c2[i] != c1[i]) {
final int charIdx = idx[c2[i]-'0'];
if (charIdx != 0) {
// move char to index 0
swap(idx, c1, charIdx);
}
// move char from 0 to i;
swap(idx, c1, i);
}
}
}

Reduce Time complexity of the following program

import java.util.Scanner;
class Special_Pairs{
private static Scanner scan;
public static void main(String [] args) {
byte t;
int n;
scan = new Scanner(System.in);
t=scan.nextByte();
int[] a=new int[100000];
while(t>0)
{
int i,j,count=0;
n=scan.nextInt();
for(i=0;i<n;i++)
{
a[i]=scan.nextInt();
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(((a[i]&a[j])==0)||((a[j]&a[i])==0))
{
count++;
}
}
}
t--;
System.out.println(count);
}
}
}
Help me reduce time complexity of this program
Question :
You have been given an integer array A on size N. You must report the number of ordered pairs (i,j) such that A[i] & A[j]=0.
Here & denotes the BITWISE AND (i,j) and (j,i) are considered different.
Input: First line contains T-Number of Test cases. First line of each test contains N. Next line contains N integers - the i'th integer A[i].
Output: Output the number of such pairs for each test case.
Constraints: T ≤ 10; N ≤ 100000; A[i] ≤ 1000000
Sample Input(Plaintext Link)
1
5
41 47 34 40 29
Sample Output(Plaintext Link)
2
Explanation: These are the required pairs (3 5) (5 3)
I would suggest three optimization for this. I have modified the code as well.
You need not to always start from 0 for each iteration of outer loop. The second loop can start from current+1 of the first loop. So will not be comparing elements which you have already compared.
You don't need to check for both pairs (i,j) and (j,i). If one is zero then other will always be zero.
You need not to initialize the array with fix size. You can always initialize it reading the value of n.
import java.util.Scanner;
public class Pairs {
public static void main(String [] args) {
Scanner scan = new Scanner(System.in);
int t = scan.nextInt();
while(t > 0) {
t--;
int count = 0;
int n = scan.nextInt();
int a[] = new int[n];
for(int i = 0; i<n; i++) {
a[i]=scan.nextInt();
}
for(int i = 0; i<n-1; i++) {
for(int j = i+1; j<n; j++) {
if((a[i] & a[j])==0)
{
count += 2;
}
}
}
System.out.println(count);
}
}
}
If you are competing on a programming contest (like ICPC or something like this), maybe you shouldn't use Scanner. It's too slow for reading from the keyboard. I've already competed at ICPC, but I used to use C++. Maybe you should try BufferedReader instead of Scanner.

Print all palindromes of size greater than equal to 3 of a given string [duplicate]

If the input is 'abba' then the possible palindromes are a, b, b, a, bb, abba.
I understand that determining if string is palindrome is easy. It would be like:
public static boolean isPalindrome(String str) {
int len = str.length();
for(int i=0; i<len/2; i++) {
if(str.charAt(i)!=str.charAt(len-i-1) {
return false;
}
return true;
}
But what is the efficient way of finding palindrome substrings?
This can be done in O(n), using Manacher's algorithm.
The main idea is a combination of dynamic programming and (as others have said already) computing maximum length of palindrome with center in a given letter.
What we really want to calculate is radius of the longest palindrome, not the length.
The radius is simply length/2 or (length - 1)/2 (for odd-length palindromes).
After computing palindrome radius pr at given position i we use already computed radiuses to find palindromes in range [i - pr ; i]. This lets us (because palindromes are, well, palindromes) skip further computation of radiuses for range [i ; i + pr].
While we search in range [i - pr ; i], there are four basic cases for each position i - k (where k is in 1,2,... pr):
no palindrome (radius = 0) at i - k
(this means radius = 0 at i + k, too)
inner palindrome, which means it fits in range
(this means radius at i + k is the same as at i - k)
outer palindrome, which means it doesn't fit in range
(this means radius at i + k is cut down to fit in range, i.e because i + k + radius > i + pr we reduce radius to pr - k)
sticky palindrome, which means i + k + radius = i + pr
(in that case we need to search for potentially bigger radius at i + k)
Full, detailed explanation would be rather long. What about some code samples? :)
I've found C++ implementation of this algorithm by Polish teacher, mgr Jerzy Wałaszek.
I've translated comments to english, added some other comments and simplified it a bit to be easier to catch the main part.
Take a look here.
Note: in case of problems understanding why this is O(n), try to look this way:
after finding radius (let's call it r) at some position, we need to iterate over r elements back, but as a result we can skip computation for r elements forward. Therefore, total number of iterated elements stays the same.
Perhaps you could iterate across potential middle character (odd length palindromes) and middle points between characters (even length palindromes) and extend each until you cannot get any further (next left and right characters don't match).
That would save a lot of computation when there are no many palidromes in the string. In such case the cost would be O(n) for sparse palidrome strings.
For palindrome dense inputs it would be O(n^2) as each position cannot be extended more than the length of the array / 2. Obviously this is even less towards the ends of the array.
public Set<String> palindromes(final String input) {
final Set<String> result = new HashSet<>();
for (int i = 0; i < input.length(); i++) {
// expanding even length palindromes:
expandPalindromes(result,input,i,i+1);
// expanding odd length palindromes:
expandPalindromes(result,input,i,i);
}
return result;
}
public void expandPalindromes(final Set<String> result, final String s, int i, int j) {
while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
result.add(s.substring(i,j+1));
i--; j++;
}
}
So, each distinct letter is already a palindrome - so you already have N + 1 palindromes, where N is the number of distinct letters (plus empty string). You can do that in single run - O(N).
Now, for non-trivial palindromes, you can test each point of your string to be a center of potential palindrome - grow in both directions - something that Valentin Ruano suggested.
This solution will take O(N^2) since each test is O(N) and number of possible "centers" is also O(N) - the center is either a letter or space between two letters, again as in Valentin's solution.
Note, there is also O(N) solution to your problem, based on Manacher's algoritm (article describes "longest palindrome", but algorithm could be used to count all of them)
I just came up with my own logic which helps to solve this problem.
Happy coding.. :-)
System.out.println("Finding all palindromes in a given string : ");
subPal("abcacbbbca");
private static void subPal(String str) {
String s1 = "";
int N = str.length(), count = 0;
Set<String> palindromeArray = new HashSet<String>();
System.out.println("Given string : " + str);
System.out.println("******** Ignoring single character as substring palindrome");
for (int i = 2; i <= N; i++) {
for (int j = 0; j <= N; j++) {
int k = i + j - 1;
if (k >= N)
continue;
s1 = str.substring(j, i + j);
if (s1.equals(new StringBuilder(s1).reverse().toString())) {
palindromeArray.add(s1);
}
}
}
System.out.println(palindromeArray);
for (String s : palindromeArray)
System.out.println(s + " - is a palindrome string.");
System.out.println("The no.of substring that are palindrome : "
+ palindromeArray.size());
}
Output:-
Finding all palindromes in a given string :
Given string : abcacbbbca
******** Ignoring single character as substring palindrome ********
[cac, acbbbca, cbbbc, bb, bcacb, bbb]
cac - is a palindrome string.
acbbbca - is a palindrome string.
cbbbc - is a palindrome string.
bb - is a palindrome string.
bcacb - is a palindrome string.
bbb - is a palindrome string.
The no.of substring that are palindrome : 6
I suggest building up from a base case and expanding until you have all of the palindomes.
There are two types of palindromes: even numbered and odd-numbered. I haven't figured out how to handle both in the same way so I'll break it up.
1) Add all single letters
2) With this list you have all of the starting points for your palindromes. Run each both of these for each index in the string (or 1 -> length-1 because you need at least 2 length):
findAllEvenFrom(int index){
int i=0;
while(true) {
//check if index-i and index+i+1 is within string bounds
if(str.charAt(index-i) != str.charAt(index+i+1))
return; // Here we found out that this index isn't a center for palindromes of >=i size, so we can give up
outputList.add(str.substring(index-i, index+i+1));
i++;
}
}
//Odd looks about the same, but with a change in the bounds.
findAllOddFrom(int index){
int i=0;
while(true) {
//check if index-i and index+i+1 is within string bounds
if(str.charAt(index-i-1) != str.charAt(index+i+1))
return;
outputList.add(str.substring(index-i-1, index+i+1));
i++;
}
}
I'm not sure if this helps the Big-O for your runtime, but it should be much more efficient than trying each substring. Worst case would be a string of all the same letter which may be worse than the "find every substring" plan, but with most inputs it will cut out most substrings because you can stop looking at one once you realize it's not the center of a palindrome.
I tried the following code and its working well for the cases
Also it handles individual characters too
Few of the cases which passed:
abaaa --> [aba, aaa, b, a, aa]
geek --> [g, e, ee, k]
abbaca --> [b, c, a, abba, bb, aca]
abaaba -->[aba, b, abaaba, a, baab, aa]
abababa -->[aba, babab, b, a, ababa, abababa, bab]
forgeeksskeegfor --> [f, g, e, ee, s, r, eksske, geeksskeeg,
o, eeksskee, ss, k, kssk]
Code
static Set<String> set = new HashSet<String>();
static String DIV = "|";
public static void main(String[] args) {
String str = "abababa";
String ext = getExtendedString(str);
// will check for even length palindromes
for(int i=2; i<ext.length()-1; i+=2) {
addPalindromes(i, 1, ext);
}
// will check for odd length palindromes including individual characters
for(int i=1; i<=ext.length()-2; i+=2) {
addPalindromes(i, 0, ext);
}
System.out.println(set);
}
/*
* Generates extended string, with dividors applied
* eg: input = abca
* output = |a|b|c|a|
*/
static String getExtendedString(String str) {
StringBuilder builder = new StringBuilder();
builder.append(DIV);
for(int i=0; i< str.length(); i++) {
builder.append(str.charAt(i));
builder.append(DIV);
}
String ext = builder.toString();
return ext;
}
/*
* Recursive matcher
* If match is found for palindrome ie char[mid-offset] = char[mid+ offset]
* Calculate further with offset+=2
*
*
*/
static void addPalindromes(int mid, int offset, String ext) {
// boundary checks
if(mid - offset <0 || mid + offset > ext.length()-1) {
return;
}
if (ext.charAt(mid-offset) == ext.charAt(mid+offset)) {
set.add(ext.substring(mid-offset, mid+offset+1).replace(DIV, ""));
addPalindromes(mid, offset+2, ext);
}
}
Hope its fine
public class PolindromeMyLogic {
static int polindromeCount = 0;
private static HashMap<Character, List<Integer>> findCharAndOccurance(
char[] charArray) {
HashMap<Character, List<Integer>> map = new HashMap<Character, List<Integer>>();
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
if (map.containsKey(c)) {
List list = map.get(c);
list.add(i);
} else {
List list = new ArrayList<Integer>();
list.add(i);
map.put(c, list);
}
}
return map;
}
private static void countPolindromeByPositions(char[] charArray,
HashMap<Character, List<Integer>> map) {
map.forEach((character, list) -> {
int n = list.size();
if (n > 1) {
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (list.get(i) + 1 == list.get(j)
|| list.get(i) + 2 == list.get(j)) {
polindromeCount++;
} else {
char[] temp = new char[(list.get(j) - list.get(i))
+ 1];
int jj = 0;
for (int ii = list.get(i); ii <= list
.get(j); ii++) {
temp[jj] = charArray[ii];
jj++;
}
if (isPolindrome(temp))
polindromeCount++;
}
}
}
}
});
}
private static boolean isPolindrome(char[] charArray) {
int n = charArray.length;
char[] temp = new char[n];
int j = 0;
for (int i = (n - 1); i >= 0; i--) {
temp[j] = charArray[i];
j++;
}
if (Arrays.equals(charArray, temp))
return true;
else
return false;
}
public static void main(String[] args) {
String str = "MADAM";
char[] charArray = str.toCharArray();
countPolindromeByPositions(charArray, findCharAndOccurance(charArray));
System.out.println(polindromeCount);
}
}
Try out this. Its my own solution.
// Maintain an Set of palindromes so that we get distinct elements at the end
// Add each char to set. Also treat that char as middle point and traverse through string to check equality of left and right char
static int palindrome(String str) {
Set<String> distinctPln = new HashSet<String>();
for (int i=0; i<str.length();i++) {
distinctPln.add(String.valueOf(str.charAt(i)));
for (int j=i-1, k=i+1; j>=0 && k<str.length(); j--, k++) {
// String of lenght 2 as palindrome
if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(j)))) {
distinctPln.add(str.substring(j,i+1));
}
// String of lenght 2 as palindrome
if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(k)))) {
distinctPln.add(str.substring(i,k+1));
}
if ( (new Character(str.charAt(j))).equals(new Character(str.charAt(k)))) {
distinctPln.add(str.substring(j,k+1));
} else {
continue;
}
}
}
Iterator<String> distinctPlnItr = distinctPln.iterator();
while ( distinctPlnItr.hasNext()) {
System.out.print(distinctPlnItr.next()+ ",");
}
return distinctPln.size();
}
Code is to find all distinct substrings which are palindrome.
Here is the code I tried. It is working fine.
import java.util.HashSet;
import java.util.Set;
public class SubstringPalindrome {
public static void main(String[] args) {
String s = "abba";
checkPalindrome(s);
}
public static int checkPalindrome(String s) {
int L = s.length();
int counter =0;
long startTime = System.currentTimeMillis();
Set<String> hs = new HashSet<String>();
// add elements to the hash set
System.out.println("Possible substrings: ");
for (int i = 0; i < L; ++i) {
for (int j = 0; j < (L - i); ++j) {
String subs = s.substring(j, i + j + 1);
counter++;
System.out.println(subs);
if(isPalindrome(subs))
hs.add(subs);
}
}
System.out.println("Total possible substrings are "+counter);
System.out.println("Total palindromic substrings are "+hs.size());
System.out.println("Possible palindromic substrings: "+hs.toString());
long endTime = System.currentTimeMillis();
System.out.println("It took " + (endTime - startTime) + " milliseconds");
return hs.size();
}
public static boolean isPalindrome(String s) {
if(s.length() == 0 || s.length() ==1)
return true;
if(s.charAt(0) == s.charAt(s.length()-1))
return isPalindrome(s.substring(1, s.length()-1));
return false;
}
}
OUTPUT:
Possible substrings:
a
b
b
a
ab
bb
ba
abb
bba
abba
Total possible substrings are 10
Total palindromic substrings are 4
Possible palindromic substrings: [bb, a, b, abba]
It took 1 milliseconds

Sum of factorials for large numbers

I want to calculate the sum of digits of N!.
I want to do this for really large values of N, say N(1500). I am not using .NET 4.0. I cannot use the BigInteger class to solve this.
Can this be solved by some other algorithm or procedure? Please help.
I want to do some thing like this Calculate the factorial of an arbitrarily large number, showing all the digits but in C#. However I am unable to solve.
There is no special magic that allows you to calculate the sum of the digits, as far as I am concerned.
It shouldn't be that hard to create your own BigInteger class anyway - you only need to implement the long multiplication algorithm from 3rd grade.
If your goal is to calculate the sum of the digits of N!, and if N is reasonably bounded, you can do the following without a BigInteger type:
Find a list of factorial values online (table lookup will be much more efficient than calculating from scratch, and does not require BigInteger)
Store as a string data type
Parse each character in the string as an integer
Add the resulting integers
There are two performance shortcuts that you can use for whatever implementation you choose.
Chop off any zeros from the numbers.
If the number is evenly divisible by 5^n, divide it by 10^n.
in this way,
16*15*14*13*12*11*10*9*8*7*6*5*4*3*2 = 20,922,789,888,000
//-->
16*1.5*14*13*12*11*1*9*8*7*6*0.5*4*3*2 = 20,922,789,888 //Sum of 63
Also, it feels like there should be some algorithm without reverting to calculating it all out. Going to 18!, the sums of the digits are:
2,6,6,3,9,9,9,27,27,36,27,27,45,45,63,63,63
//the sums of the resulting digits are:
2,6,6,3,9,9,9,9,9,9,9,9,9,9,9,9,9
and notably, the sum of the digits of 1500! is 16749 (the sum of whose digits are 27)
Here's some working code. Some components can be improved upon to increase efficiency. The idea is to use whatever multiplication algorithm I was told in school, and to store long integers as strings.
As an afterthought, I think it would be smarter to represent large numbers with List<int>() instead of string. But I'll leave that as an exercise to the reader.
Code Sample
static string Mult(string a, string b)
{
int shift = 0;
List<int> result = new List<int>();
foreach (int aDigit in a.Reverse().Select(c => int.Parse(c.ToString())))
{
List<int> subresult = new List<int>();
int store = 0;
foreach (int bDigit in b.Reverse().Select(c => int.Parse(c.ToString())))
{
int next = aDigit*bDigit + store;
subresult.Add(next%10);
store = next/10;
}
if (store != 0) subresult.Add(store);
subresult.Reverse();
for (int i = 0; i < shift; ++i) subresult.Add(0);
subresult.Reverse();
int newResult = new List<int>();
store = 0;
for (int i = 0; i < subresult.Count; ++i)
{
if (result.Count >= i + 1)
{
int next = subresult[i] + result[i] + store;
if (next >= 10)
newResult.Add(next % 10);
else newResult.Add(next);
store = next / 10;
}
else
{
int next = subresult[i] + store;
newResult.Add(next % 10);
store = next / 10;
}
}
if (store != 0) newResult.Add(store);
result = newResult;
++shift;
}
result.Reverse();
return string.Join("", result);
}
static int FactorialSum(int n)
{
string result = "1";
for (int i = 2; i <= n; i++)
result = Mult(i.ToString(), result);
return result.Sum(r => int.Parse(r.ToString()));
}
Code Testing
Assuming the code snippet above is in the same class as your Main method, call it thusly.
Input
static void Main(string[] args)
{
Console.WriteLine(FactorialSum(1500));
}
Output
16749
Here's a port of the C++ code you reference in one of your comments. One thing to realize when porting from C++ to C# is that integers that are zero evaluate to false and integers that are non-zero evaluate to true when used in a Boolean comparison.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ArbitraryFactorial
{
class Program
{
const int max = 5000;
static void display(int[] arr)
{
int ctr = 0;
for (int i = 0; i < max; i++)
{
if (ctr == 0 && arr[i] != 0) ctr = 1;
if (ctr != 0)
Console.Write(arr[i]);
}
}
static void factorial(int[] arr, int n)
{
if (n == 0) return;
int carry = 0;
for (int i = max - 1; i >= 0; --i)
{
arr[i] = (arr[i] * n) + carry;
carry = arr[i] / 10;
arr[i] %= 10;
}
factorial(arr, n - 1);
}
static void Main(string[] args)
{
int[] arr = new int[max];
arr[max - 1] = 1;
int num;
Console.Write("Enter the number: ");
num = int.Parse(Console.ReadLine());
Console.Write("Factorial of " + num + " is: ");
factorial(arr, num);
display(arr);
}
}
}
you can find the source code at : http://codingloverlavi.blogspot.in/2013/03/here-is-one-more-interesting-program.html
#include<stdio.h>
#include<conio.h>
#include<iostream.h>
#include<time.h>
#define max 5000
void multiply(long int *,long int);
void factorial(long int *,long int);
int main()
{
clrscr();
cout<<"PROGRAM TO CALCULATE FACTORIAL OF A NUMBER";
cout<<"\nENTER THE NUMBER\n";
long int num;
cin>>num;
long int a[max];
for(long int i=0;i<max;i++)
a[i]=0;
factorial(a,num);
clrscr();
//PRINTING THE FINAL ARRAY...:):):)
cout<<"THE FACTORIAL OF "<<num<<" is "<<endl<<endl;
long int flag=0;
int ans=0;
for(i=0;i<max;i++)
{
if(flag||a[i]!=0)
{
flag=1;
cout<<a[i];
ans=ans+a[i];
}
}
cout<<endl<<endl<<"the sum of all digits is: "<<ans;
getch();
return 1;
}
void factorial(long int *a,long int n)
{
long int lavish;
long int num=n;
lavish=n;
for(long int i=max-1;i>=0&&n;i--)
{
a[i]=n%10;
n=n/10;
}
for(i=2;i<(lavish);i++)
{
multiply(a,num-1);
num=num-1;
}
}
void multiply(long int *a,long int n)
{
for(long int i=0;i<max;i++)
a[i]=a[i]*n;
for(i=max-1;i>0;i--)
{
a[i-1]=a[i-1]+(a[i]/10);
a[i]=a[i]%10;
}
}
You can't use these numbers at all without a BigInteger type.
No algorithm or procedure can squeeze numbers larger than 264 into a long.
You need to find a BigInteger implementation for .Net 3.5.

Algorithm to iterate through sample space of numbers

I hope this isn't a dupe, but it's hard to boil down the problem into keywords!
This is always something that I've wondered about. Let's say you have a black box that takes n integers as an input (where n > 1). Given that there is a bounds on the integer values, how would you go about writing an algorithm that will push the entire sample space through the black box? (bonus points if n can be specified at runtime)
My attempt when n = 2 is as follows:
int min = 0;
int max = 9;
int a = min;
int b = min;
while(a <= max && b <= max)
{
blackBox(a, b);
a++;
if(a > max)
{
a = min;
b++;
}
}
The above code is fine for two variables, but as you might guess, my algorithm gets really ugly when n approaches double-digits.
Is there a better way to do this other than nesting if statements like I have done?
I know a bad way to do it, which would be to randomly generate the values for each iteration and save the inputs of previous iterations so you don't poke the black box with the same variables twice. However, I was hoping for a more speedy method as collisions really hurt the execution time as the number of unique black box calls approaches (max - min + 1) ^ n
Why not used nested loops? Then you just add more nested loops as necessary.
Might not be overly efficent but you did indicate you need to cover the entire sample space, so you're going to have to run every possible combination of values of the input variables anway - so I doubt there's much you can do about efficency unless it's possible to only evaluate against a portion of the state space.
int min = 0;
int max = 9;
for( int a = min ; a <= max ; ++a )
for( int b = min ; b <= max ; ++b )
blackBox( a , b );
Also, I think you'll find the number of unique calls is (max - min + 1) ^ n, not the other way around.
Edit:
A different run-time version to that already suggested
Imre L seems to have hit the nail on the head for a real-time version using the same language type as your question (something C-like), but since you've tagged this as language agnostic I've decided to try something different (also, I'm learning Python at the moment so was looking for an excuse to practice).
Here's a Python real-time version, in each case x will be a n-tuple, such as [1,0,3,2]. Only thing I will say is this does not include max in the state-space (in the example below it will use 0 to 2 inclusive, not 3) so you'd have to increment max before use.
import itertools
min = 0
max = 3
n = 4
for x in itertools.product(range(min,max), repeat=n):
blackBox( x )
The numbers will be held in array a that will be set dynamically eg: int a[] = new int[n]
If the blackBox cannot be modified to take a sample as array then you can either write an ugly wrapper function for calling it with different count of parameters or you are pretty much out of luck for doing it dynamically.
(Procedural) Pseudo code:
int min = 0;
int max = 9;
int a[] = array();
int count = length(a);
setToMinValue(a);
while(a[count-1] <= max)
{
blackBox(a); // or bb(a[0],a[1],...)
a[0]++;
//while next number needs to be increased
for (int i = 0; a[i] > max && i < count-1; i++) {
a[i] = min;
a[i+1]++;
}
}
Here is a generic solution, in Java:
public class Counter implements Iterator<int[]> {
private int[] max;
private int[] vector;
public Counter(int[] maxValues) {
this.max = maxValues;
this.vector = new int[maxValues.length];
}
public int[] next() {
if (!hasNext())
throw new NoSuchElementException();
int[] res = vector.clone();
int i = 0;
while (i < vector.length && vector[i] == max[i]) {
vector[i] = 0;
i++;
}
if (i == vector.length)
vector = null;
else
vector[i]++;
return res;
}
#Override
public boolean hasNext() {
return (vector != null);
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
public static void main(String[] args) {
Counter c = new Counter(new int[]{3});
while (c.hasNext()) {
System.out.println(Arrays.toString(c.next()));
}
}
}
The constructor receives the maximum values for each position. The minimum is always 0 (therefore you can use it to simulate a counter in any radix, and in any "mixed radix"). I added a usage example at the bottom.
You may think of each input to the black box as an n-digit number in a max - min + 1 radix system. For example, if min = 3 and max = 12, then max - min + 1 == 10 and each input to the black box corresponds to an n-digit number in the decimal system. Simply iterate over all the numbers from 0 to (max - min + 1)^n, decode each number and feed the resulting vector to the black box.
Here's a Java implementation:
public static interface BlackBox {
void consume(int... vector);
}
public static void iterateSample(int min, int max, int n, BlackBox bb) {
int radix = max - min + 1;
long limit = (long) Math.pow(radix, n); /* Imprecise for larger numbers! */
for (int i = 0; i < limit; i++) {
int encoded = i;
int[] decoded = new int[n];
for (int j = 0; j < n; j++) {
decoded[j] = min + (encoded % radix);
encoded /= radix;
}
bb.consume(decoded);
}
}

Resources