Project Euler 7 Scala Problem - arrays

I was trying to solve Project Euler problem number 7 using scala 2.8
First solution implemented by me takes ~8 seconds
def problem_7:Int = {
var num = 17;
var primes = new ArrayBuffer[Int]();
primes += 2
primes += 3
primes += 5
primes += 7
primes += 11
primes += 13
while (primes.size < 10001){
if (isPrime(num, primes)) primes += num
if (isPrime(num+2, primes)) primes += num+2
num += 6
}
return primes.last;
}
def isPrime(num:Int, primes:ArrayBuffer[Int]):Boolean = {
// if n == 2 return false;
// if n == 3 return false;
var r = Math.sqrt(num)
for (i <- primes){
if(i <= r ){
if (num % i == 0) return false;
}
}
return true;
}
Later I tried the same problem without storing prime numbers in array buffer. This take .118 seconds.
def problem_7_alt:Int = {
var limit = 10001;
var count = 6;
var num:Int = 17;
while(count < limit){
if (isPrime2(num)) count += 1;
if (isPrime2(num+2)) count += 1;
num += 6;
}
return num;
}
def isPrime2(n:Int):Boolean = {
// if n == 2 return false;
// if n == 3 return false;
var r = Math.sqrt(n)
var f = 5;
while (f <= r){
if (n % f == 0) {
return false;
} else if (n % (f+2) == 0) {
return false;
}
f += 6;
}
return true;
}
I tried using various mutable array/list implementations in Scala but was not able to make solution one faster. I do not think that storing Int in a array of size 10001 can make program slow. Is there some better way to use lists/arrays in scala?

The problem here is that ArrayBuffer is parameterized, so what it really stores are references to Object. Any reference to an Int is automatically boxed and unboxed as needed, which makes it very slow. It is incredibly slow with Scala 2.7, which uses a Java primitive to do that, which does it very slowly. Scala 2.8 takes another approach, making it faster. But any boxing/unboxing will slow you down. Furthermore, you are first looking up the ArrayBuffer in the heap, and then looking up again for java.lang.Integer containing the Int -- two memory accesses, which makes it way slower than your other solution.
When Scala collections become specialized, it should be plenty faster. Whether it should be enough to beat your second version or not, I don't know.
Now, what you may do to get around that is to use Array instead. Because Java's Array are not erased, you avoid the boxing/unboxing.
Also, when you use for-comprehensions, your code is effectively stored in a method which is called for each element. So you are also making many method calls, which is another reason this is slower. Alas, someone wrote a plugin for Scala which optimizes at least one case of for-comprehensions to avoid that.

Using Array should make it work in about zero seconds with the right algorithm. This, for example, takes about 7 milliseconds on my system:
class Primes(bufsize: Int) {
var n = 1
val pbuf = new Array[Int](bufsize max 1)
pbuf(0) = 2
def isPrime(num: Int): Boolean = {
var i = 0
while (i < n && pbuf(i)*pbuf(i) <= num) {
if (num % pbuf(i) == 0) return false
i += 1
}
if (pbuf(i)*pbuf(i) < num) {
i = pbuf(i)
while (i*i <= num) {
if (num % i == 0) return false
i += 2
}
}
return true;
}
def fillBuf {
var i = 3
n = 1
while (n < bufsize) {
if (isPrime(i)) { pbuf(n) = i; n += 1 }
i += 2
}
}
def lastPrime = { if (n<bufsize) fillBuf ; pbuf(pbuf.length-1) }
}
object Primes {
def timedGet(num: Int) = {
val t0 = System.nanoTime
val p = (new Primes(num)).lastPrime
val t1 = System.nanoTime
(p , (t1-t0)*1e-9)
}
}
Result (on second call; first has some overhead):
scala> Primes.timedGet(10001)
res1: (Int, Double) = (104743,0.00683394)

I think you have to think out of the box :)
Because the problem is manageable, you can use Sieve of Eratosthenes to solve it very efficiently.

Here's a recursive solution (using the isPrime function from your first solution). It seems to be good Scala style to prefer immutability (i.e. to try not to use vars) so I've done that here (in fact there are no vars or vals!). I don't have a Scala installation here though so can't tell if this is actually any quicker!
def problem_7:Int = {
def isPrime_(n: Int) = (n % 6 == 1 || n % 6 == 5) && isPrime(n)
def process(n: Int, acc: List[Int]): Int = {
if (acc.size == 10001) acc.head
else process(n+1, if isPrime_(n) n :: acc else acc)
}
process(1, Nil)
}

Related

Given a list of numbers and a number k, return whether any two numbers from the list add up to k

This question was asked in the Google programming interview. I thought of two approaches for the same:
Find all the subsequences of length. While doing so compute the sum and of the two elements and check if it is equal to k. If ye, print Yes, else keep searching. This is a brute Force approach.
Sort the array in non-decreasing order. Then start traversing the array from its right end. Say we have the sorted array, {3,5,7,10} and we want the sum to be 17. We will start from element 10, index=3, let's denote the index with 'j'. Then include the current element and compute required_sum= sum - current_element. After that, we can perform a binary or ternary search in array[0- (j-1)] to find if there is an element whose value is equal to the required_sum. If we find such an element, we can break as we have found a subsequence of length 2 whose sum is the given sum. If we don't find any such element, then decrease the index of j and repeat the above-mentioned steps for resulting subarray of length= length-1 i.e. by excluding the element at index 3 in this case.
Here we have considered that array could have negative as well as positive integers.
Can you suggest a better solution than this? A DP solution maybe? A solution that can further reduce it's time complexity.
This question can be easily solved with the help of set in O(N) time and space complexity.First add all the elements of array into set and then traverse each element of array and check whether K-ar[i] is present in set or not.
Here is the code in java with O(N) complexity :
boolean flag=false;
HashSet<Long> hashSet = new HashSet<>();
for(int i=0;i<n;i++){
if(hashSet.contains(k-ar[i]))flag=true;
hashSet.add(ar[i]);
}
if(flag)out.println("YES PRESENT");
else out.println("NOT PRESENT");
Here is a Java implementation with the same time complexity as the algorithm used to sort the array. Note that this is faster than your second idea because we do not need to search the entire array for a matching partner each time we examine a number.
public static boolean containsPairWithSum(int[] a, int x) {
Arrays.sort(a);
for (int i = 0, j = a.length - 1; i < j;) {
int sum = a[i] + a[j];
if (sum < x)
i++;
else if (sum > x)
j--;
else
return true;
}
return false;
}
Proof by induction:
Let a[0,n] be an array of length n+1 and p = (p1, p2) where p1, p2 are integers and p1 <= p2 (w.l.o.g.). Assume a[0,n] contains p1 and p2. In the case that it does not, the algorithm is obviously correct.
Base case (i = 0, j = n):
a[0,-1] does not contain p1 and a[n,n+1] does not contain p2.
Hypothesis:
a[0,i-1] does not contain a[i] and a[j+1,n] does not contain p2.
Step case (i to i + 1 or j to j - 1):
Assume p1 = a[i]. Then, since p1 + a[j] < p1 + p2, index j must be increased. But from the hypothesis we know that a[j+1,n-1] does not contain p2. Contradiction. It follows that p1 != a[i].
j to j - 1 analogously.
Because each iteration, a[0,i-1] and a[j+1,n], does not contain p1, and p2, a[i,j] does contain p1 and p2. Eventually, a[i] = p1 and a[j] = p2 and the algorithm returns true.
This is java implementation with O(n) Time complexity and O(n) space. The idea is have a HashMap which will contain complements of every array element w.r.t target. If the complement is found, we have 2 array elements which sum to the target.
public boolean twoSum(int[] nums, int target) {
if(nums.length == 0 || nums == null) return false;
Map<Integer, Integer> complementMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int curr = nums[i];
if(complementMap.containsKey(target - curr)){
return true;
}
complementMap.put(curr, i);
}
return false;
}
if you want to find pair count,
pairs = [3,5,7,10]
k = 17
counter = 0
for i in pairs:
if k - i in pairs:
counter += 1
print(counter//2)
Python Solution:
def FindPairs(arr, k):
for i in range(0, len(arr)):
if k - arr[i] in arr:
return True
return False
A = [1, 4, 45, 6, 10, 8]
n = 100
print(FindPairs(A, n))
Or
def findpair(list1, k):
for i in range(0, len(list1)):
for j in range(0, len(list1)):
if k == list1[i] + list1[j]:
return True
return False
nums = [10, 5, 6, 7, 3]
k = 100
print(findpair(nums, k))
Here is python's implementation
arr=[3,5,7,10]
k=17
flag=False
hashset = set()
for i in range(0,len(arr)):
if k-arr[i] in hashset:
flag=True
hashset.add(arr[i])
print( flag )
Javascript solution:
function hasSumK(arr, k) {
hashMap = {};
for (let value of arr) {
if (hashMap[value]) { return true;} else { hashMap[k - value] = true };
}
return false;
}
Using Scala, in a single pass with O(n) time and space complexity.
import collection.mutable.HashMap
def addUpToK(arr: Array[Int], k: Int): Option[Int] = {
val arrayHelper = new HashMap[Int,Int]()
def addUpToKHelper( i: Int): Option[Int] = {
if(i < arr.length){
if(arrayHelper contains k-arr(i) ){
Some(arr(i))
}else{
arrayHelper += (arr(i) -> (k-arr(i)) )
addUpToKHelper( i+1)
}
}else{
None
}
}
addUpToKHelper(0)
}
addUpToK(Array(10, 15, 3, 7), 17)
C++ solution:
int main(){
int n;
cin>>n;
int arr[n];
for(int i = 0; i < n; i++)
{
cin>>arr[i];
}
int k;
cin>>k;
int t = false;
for(int i = 0; i < n-1; i++)
{
int s = k-arr[i];
for(int j = i+1; j < n; j++)
{
if(s==arr[j])
t=true;
}
}
if (t){
cout<<"Thank you C++, very cool";
}
else{
cout<<"Damn it!";
}
return 0;
}
Python code:
L = list(map(int,input("Enter List: ").split()))
k = int(input("Enter value: "))
for i in L:
if (k - i) in L:
print("True",k-i,i)
Here is Swift solution:
func checkTwoSum(array: [Int], k: Int) -> Bool {
var foundPair = false
for n in array {
if array.contains(k - n) {
foundPair = true
break
} else {
foundPair = false
}
}
return foundPair
}
def sum_total(list, total):
dict = {}
for i in lista:
if (total - i) in dict:
return True
else:
dict[i] = i
return False
Here is a C implementationFor Sorting O(n2) time and space complexity.For Solving Problem We use
single pass with O(n) time and space complexity via Recursion.
/* Given a list of numbers and a number k , return weather any two numbers from the list add up to k.
For example, given [10,15,3,7] and k of 17 , return 10 + 7 is 17
Bonus: Can You Do in one pass ? */
#include<stdio.h>
int rec(int i , int j ,int k , int n,int array[])
{
int sum;
for( i = 0 ; i<j ;)
{
sum = array[i] + array[j];
if( sum > k)
{
j--;
}else if( sum < k)
{
i++;
}else if( sum == k )
{
printf("Value equal to sum of array[%d] = %d and array[%d] = %d",i,array[i],j,array[j]);
return 1;//True
}
}
return 0;//False
}
int main()
{
int n ;
printf("Enter The Value of Number of Arrays = ");
scanf("%d",&n);
int array[n],i,j,k,x;
printf("Enter the Number Which you Want to search in addition of Two Number = ");
scanf("%d",&x);
printf("Enter The Value of Array \n");
for( i = 0 ; i <=n-1;i++)
{
printf("Array[%d] = ",i);
scanf("%d",&array[i]);
}
//Sorting of Array
for( i = 0 ; i <=n-1;i++)
{
for( j = 0 ; j <=n-i-1;j++)
{
if( array[j]>array[j+1])
{
//swapping of two using bitwise operator
array[j] = array[j]^array[j+1];
array[j+1] = array[j]^array[j+1];
array[j] = array[j]^array[j+1];
}
}
}
k = x ;
j = n-1;
rec(i,j,k,n,array);
return 0 ;
}
OUTPUT
Enter The Value of Number of Arrays = 4
Enter the Number Which you Want to search in addition of Two Number = 17
Enter The Value of Array
Array[0] = 10
Array[1] = 15
Array[2] = 3
Array[3] = 7
Value equal to sum of array[1] = 7 and array[2] = 10
Process returned 0 (0x0) execution time : 54.206 s
Press any key to continue.
The solution can be found out in just one pass of the array. Initialise a hash Set and start iterating the array. If the current element in the array is found in the set then return true, else add the complement of this element (x - arr[i]) to the set. If the iteration of array ended without returning it means that there is no such pair whose sum is equal to x so return false.
public boolean containsPairWithSum(int[] a, int x) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i< a.length; i++) {
if(set.contains(a[i]))
return true;
set.add(x - a[i]);
}
return false;
}
Here's Python. O(n). Need to remove the current element whilst looping because the list might not have duplicate numbers.
def if_sum_is_k(list, k):
i = 0
list_temp = list.copy()
match = False
for e in list:
list_temp.pop(i)
if k - e in list_temp:
match = True
i += 1
list_temp = list.copy()
return match
I came up with two solutions in C++. One was a naive brute force type which was in O(n^2) time.
int main() {
int N,K;
vector<int> list;
cin >> N >> K;
clock_t tStart = clock();
for(int i = 0;i<N;i++) {
list.push_back(i+1);
}
for(int i = 0;i<N;i++) {
for(int j = 0;j<N;j++) {
if(list[i] + list[j] == K) {
cout << list[i] << " " << list[j] << endl;
cout << "YES" << endl;
printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
return 0;
}
}
}
cout << "NO" << endl;
printf("Time taken: %f\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
return 0;}
This solution as you could imagine will take a large amount of time on higher values of input.
My second solution I was able to implement in O(N) time. Using an unordered_set, much like the above solution.
#include <iostream>
#include <unordered_set>
#include <time.h>
using namespace std;
int main() {
int N,K;
int trig = 0;
int a,b;
time_t tStart = clock();
unordered_set<int> u;
cin >> N >> K;
for(int i = 1;i<=N;i++) {
if(u.find(abs(K - i)) != u.end()) {
trig = 1;
a = i;
b = abs(K - i);
}
u.insert(i);
}
trig ? cout << "YES" : cout << "NO";
cout << endl;
cout << a << " " << b << endl;
printf("Time taken %fs\n",(double) (clock() - tStart)/CLOCKS_PER_SEC);
return 0;
}
Python Implementation:
The code would execute in O(n) complexity with the use of dictionary. We would be storing the (desired_output - current_input) as the key in the dictionary. And then we would check if the number exists in the dictionary or not. Search in a dictionary has an average complexity as O(1).
def PairToSumK(numList,requiredSum):
dictionary={}
for num in numList:
if requiredSum-num not in dictionary:
dictionary[requiredSum-num]=0
if num in dictionary:
print(num,requiredSum-num)
return True
return False
arr=[10, 5, 3, 7, 3]
print(PairToSumK(arr,6))
Javascript
const findPair = (array, k) => {
array.sort((a, b) => a - b);
let left = 0;
let right = array.length - 1;
while (left < right) {
const sum = array[left] + array[right];
if (sum === k) {
return true;
} else if (sum < k) {
left += 1;
} else {
right -= 1;
}
}
return false;
}
Using HashSet in java we can do it in one go or with time complexity of O(n)
import java.util.Arrays;
import java.util.HashSet;
public class One {
public static void main(String[] args) {
sumPairsInOne(10, new Integer[]{8, 4, 3, 7});
}
public static void sumPairsInOne(int sum, Integer[] nums) {
HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(nums));
//adding values to a hash set
for (Integer num : nums) {
if (set.contains(sum - num)) {
System.out.print("Found sum pair => ");
System.out.println(num + " + " + (sum - num) + " = " + sum);
return;
}
}
System.out.println("No matching pairs");
}
}
Python
def add(num, k):
for i in range(len(num)):
for j in range(len(num)):
if num[i] + num[j] == k:
return True
return False
C# solution:
bool flag = false;
var list = new List<int> { 10, 15, 3, 4 };
Console.WriteLine("Enter K");
int k = int.Parse(Console.ReadLine());
foreach (var item in list)
{
flag = list.Contains(k - item);
if (flag)
{
Console.WriteLine("Result: " + flag);
return;
}
}
Console.WriteLine(flag);
My C# Implementation:
bool isPairPresent(int[] numbers,int value)
{
for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers.Length; j++)
{
if (value - numbers[i] == numbers[j])
return true;
}
}
return false;
}
Here's a javascript solution:
function ProblemOne_Solve()
{
const k = 17;
const values = [10, 15, 3, 8, 2];
for (i=0; i<values.length; i++) {
if (values.find((sum) => { return k-values[i] === sum} )) return true;
}
return false;
}
I implemented with Scala
def hasSome(xs: List[Int], k: Int): Boolean = {
def check(xs: List[Int], k: Int, expectedSet: Set[Int]): Boolean = {
xs match {
case List() => false
case head :: _ if expectedSet contains head => true
case head :: tail => check(tail, k, expectedSet + (k - head))
}
}
check(xs, k, Set())
}
I have tried the solution in Go Lang. However, it consumes O(n^2) time.
package main
import "fmt"
func twoNosAddUptoK(arr []int, k int) bool{
// O(N^2)
for i:=0; i<len(arr); i++{
for j:=1; j<len(arr);j++ {
if arr[i]+arr[j] ==k{
return true
}
}
}
return false
}
func main(){
xs := []int{10, 15, 3, 7}
fmt.Println(twoNosAddUptoK(xs, 17))
}
Here's two very quick Python implementations (which account for the case that inputs of [1,2] and 2 should return false; in other words, you can't just double a number, since it specifies "any two").
This first one loops through the list of terms and adds each term to all of the previously seen terms until it hits the desired sum.
def do_they_add(terms, result):
first_terms = []
for second_term in terms:
for first_term in first_terms:
if second_term + first_term == result:
return True
first_terms.append(second_term)
return False
This one subtracts each term from the result until it reaches a difference that is in the list of terms (using the rule that a+b=c -> c-a=b). The use of enumerate and the odd list indexing is to exclude the current value, per the first sentence in this answer.
def do_they_add_alt(terms, result):
for i, term in enumerate(terms):
diff = result - term
if diff in [*terms[:i - 1], *terms[i + 1:]]:
return True
return False
If you do allow adding a number to itself, then the second implementation could be simplified to:
def do_they_add_alt(terms, result):
for term in terms:
diff = result - term
if diff in terms:
return True
return False
solution in javascript
this function takes 2 parameters and loop through the length of list and inside the loop there is another loop which adds one number to other numbers in the list and check there sum if its equal to k or not
const list = [10, 15, 3, 7];
const k = 17;
function matchSum(list, k){
for (var i = 0; i < list.length; i++) {
list.forEach(num => {
if (num != list[i]) {
if (list[i] + num == k) {
console.log(`${num} + ${list[i]} = ${k} (true)`);
}
}
})
}
}
matchSum(list, k);
My answer to Daily Coding Problem
# Python 2.7
def pairSumK (arr, goal):
return any(map(lambda x: (goal - x) in arr, arr))
arr = [10, 15, 3, 7]
print pairSumK(arr, 17)
Here is the code in Python 3.7 with O(N) complexity :
def findsome(arr,k):
if len(arr)<2:
return False;
for e in arr:
if k>e and (k-e) in arr:
return True
return False
and also best case code in Python 3.7 with O(N^2) complexity :
def findsomen2 (arr,k):
if len(arr)>1:
j=0
if arr[j] <k:
while j<len(arr):
i =0
while i < len(arr):
if arr[j]+arr[i]==k:
return True
i +=1
j +=1
return False
Javascript Solution
function matchSum(arr, k){
for( var i=0; i < arr.length; i++ ){
for(var j= i+1; j < arr.length; j++){
if (arr[i] + arr[j] === k){
return true;
}
}
}
return false;
}

Given a total and an array of integers what is the best algorithm to find the subset of integers whose sum is equal or closest to the total? [duplicate]

I'm having a problem with counting which is continuation of this question. I am not really a math person so it's really hard for me to figure out this subset sum problem which was suggested as resolution.
I'm having 4 ArrayList in which I hold data: alId, alTransaction, alNumber, alPrice
Type | Transaction | Number | Price
8 | Buy | 95.00000000 | 305.00000000
8 | Buy | 126.00000000 | 305.00000000
8 | Buy | 93.00000000 | 306.00000000
8 | Transfer out | 221.00000000 | 305.00000000
8 | Transfer in | 221.00000000 | 305.00000000
8 | Sell | 93.00000000 | 360.00000000
8 | Sell | 95.00000000 | 360.00000000
8 | Sell | 126.00000000 | 360.00000000
8 | Buy | 276.00000000 | 380.00000000
In the end I'm trying to get what's left for customer and what's left I put into 3 array lists:
- alNewHowMuch (corresponds to alNumber),
- alNewPrice (corresponds to alPrice),
- alNewInID (corrseponds to alID)
ArrayList alNewHowMuch = new ArrayList();
ArrayList alNewPrice = new ArrayList();
ArrayList alNewInID = new ArrayList();
for (int i = 0; i < alTransaction.Count; i++) {
string transaction = (string) alTransaction[i];
string id = (string) alID[i];
decimal price = (decimal) alPrice[i];
decimal number = (decimal) alNumber[i];
switch (transaction) {
case "Transfer out":
case "Sell":
int index = alNewHowMuch.IndexOf(number);
if (index != -1) {
alNewHowMuch.RemoveAt(index);
alNewPrice.RemoveAt(index);
alNewInID.RemoveAt(index);
} else {
ArrayList alTemp = new ArrayList();
decimal sum = 0;
for (int j = 0; j < alNewHowMuch.Count; j ++) {
string tempid = (string) alNewInID[j];
decimal tempPrice = (decimal) alNewPrice[j];
decimal tempNumbers = (decimal) alNewHowMuch[j];
if (id == tempid && tempPrice == price) {
alTemp.Add(j);
sum = sum + tempNumbers;
}
}
if (sum == number) {
for (int j = alTemp.Count - 1; j >= 0; j --) {
int tempIndex = (int) alTemp[j];
alNewHowMuch.RemoveAt(tempIndex);
alNewPrice.RemoveAt(tempIndex);
alNewInID.RemoveAt(tempIndex);
}
}
}
break;
case "Transfer In":
case "Buy":
alNewHowMuch.Add(number);
alNewPrice.Add(price);
alNewInID.Add(id);
break;
}
}
Basically I'm adding and removing things from Array depending on Transaction Type, Transaction ID and Numbers. I'm adding numbers to ArrayList like 156, 340 (when it is TransferIn or Buy) etc and then i remove them doing it like 156, 340 (when it's TransferOut, Sell). My solution works for that without a problem. The problem I have is that for some old data employees were entering sum's like 1500 instead of 500+400+100+500. How would I change it so that when there's Sell/TransferOut or Buy/Transfer In and there's no match inside ArrayList it should try to add multiple items from thatArrayList and find elements that combine into aggregate.
Inside my code I tried to resolve that problem with simple summing everything when there's no match (index == 1)
int index = alNewHowMuch.IndexOf(number);
if (index != -1) {
alNewHowMuch.RemoveAt(index);
alNewPrice.RemoveAt(index);
alNewInID.RemoveAt(index);
} else {
ArrayList alTemp = new ArrayList();
decimal sum = 0;
for (int j = 0; j < alNewHowMuch.Count; j ++) {
string tempid = (string) alNewInID[j];
decimal tempPrice = (decimal) alNewPrice[j];
decimal tempNumbers = (decimal) alNewHowMuch[j];
if (id == tempid && tempPrice == price) {
alTemp.Add(j);
sum = sum + tempNumbers;
}
}
if (sum == number) {
for (int j = alTemp.Count - 1; j >= 0; j --) {
int tempIndex = (int) alTemp[j];
alNewHowMuch.RemoveAt(tempIndex);
alNewPrice.RemoveAt(tempIndex);
alNewInID.RemoveAt(tempIndex);
}
}
}
But it only works if certain conditions are met, and fails for the rest.
Edit: Since some of you were so astonished (and blinded) by my polish variable names i translated all of them to english for simplicity and visiblity. Hopefully this will help me to get some help :-)
Here is my algorithm. It runs in O(2^(n/2)) and solves SubsetSum(1000, list-of-1000-ones) in 20 milliseconds. See the comments at the end of IVlad's post.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace SubsetSum
{
class Program
{
static void Main(string[] args)
{
var ns = new List<int>();
for (int i = 0; i < 1000; i++) ns.Add(1);
var s1 = Stopwatch.StartNew();
bool result = SubsetSum(ns, 1000);
s1.Stop();
Console.WriteLine(result);
Console.WriteLine(s1.Elapsed);
Console.Read();
}
static bool SubsetSum(ist<int> nums, int targetL)
{
var left = new List<int> { 0 };
var right = new List<int> { 0 };
foreach (var n in nums)
{
if (left.Count < right.Count) left = Insert(n, left);
else right = Insert(n, right);
}
int lefti = 0, righti = right.Count - 1;
while (lefti < left.Count && righti >= 0)
{
int s = left[lefti] + right[righti];
if (s < target) lefti++;
else if (s > target) righti--;
else return true;
}
return false;
}
static List<int> Insert(int num, List<int> nums)
{
var result = new List<int>();
int lefti = 0, left = nums[0]+num;
for (var righti = 0; righti < nums.Count; righti++)
{
int right = nums[righti];
while (left < right)
{
result.Add(left);
left = nums[++lefti] + num;
}
if (right != left) result.Add(right);
}
while (lefti < nums.Count) result.Add(nums[lefti++] + num);
return result;
}
}
}
And here is an improved version that prunes the sets:
static bool SubsetSum(List<int> nums, int target)
{
var remainingSum = nums.Sum();
var left = new List<int> { 0 };
var right = new List<int> { 0 };
foreach (var n in nums)
{
if (left.Count == 0 || right.Count == 0) return false;
remainingSum -= n;
if (left.Count < right.Count) left = Insert(n, left, target - remainingSum - right.Last(), target);
else right = Insert(n, right, target - remainingSum - left.Last(), target);
}
int lefti = 0, righti = right.Count - 1;
while (lefti < left.Count && righti >= 0)
{
int s = left[lefti] + right[righti];
if (s < target) lefti++;
else if (s > target) righti--;
else return true;
}
return false;
}
static List<int> Insert(int num, List<int> nums, int min, int max)
{
var result = new List<int>();
int lefti = 0, left = nums[0]+num;
for (var righti = 0; righti < nums.Count; righti++)
{
int right = nums[righti];
while (left < right)
{
if (min <= left && left <= max) result.Add(left);
left = nums[++lefti] + num;
}
if (right != left && min <= right && right <= max) result.Add(right);
}
while (lefti < nums.Count)
{
left = nums[lefti++] + num;
if (min <= left && left <= max) result.Add(left);
}
return result;
}
This last one solved the problem with 100000 ones in about 5 milliseconds (but this is a best case of the algorithm, with real world data it will be slower).
For your use this algorithm is probably fast enough (and I don't see any obvious improvements). If you enter 10,000 products with a random price between 0 and 20 and your goal is to sum to 500 this is solved in 0.04 seconds on my laptop.
Edit: I just read on Wikipedia that the best known algorithm is O(2^(n/2)*n). This one is O(2^(n/2)). Do I get the Turing Award?
How you should do this depends on a number important things: how many numbers will you have and how big will they be? Also, as far as I understand, your data can change (add / remove numbers etc.), right?. How often do you need to make these queries?
I'll present two solutions. I suggest you use the second, as I suspect it's better for what you need and it's a lot easier to understand.
Solution 1 - dynamic programming
Let S[i] = true if we can make sum i and false otherwise.
S[0] = true // we can always make sum 0: just don't choose any number
S[i] = false for all i != 0
for each number i in your input
for s = MaxSum downto i
if ( S[s - i] == true )
S[s] = true; // if we can make the sum s - i, we can also make the sum s by adding i to the sum s - i.
To get the actual numbers that make up your sum you should keep another vector P[i] = the last number that was used to make sum i. You would update this accordingly in the if condition above.
The time complexity of this is O(numberOfNumbers * maxSumOfAllNumbers), which is pretty bad, especially since you have to rerun this algorithm whenever your data changes. It's also slow for even one run as long as your numbers can be very big and you can have a lot of them. In fact, "a lot" is misleading. If you have 100 numbers and each number can be as big as 10 000, you will do roughly 100 * 10 000 = 1 000 000 operations each time your data changes.
It's a good solution to know, but not really useful in practice, or at least not in your case I think.
He's some C# for the approach I suggest:
class Program
{
static void Main(string[] args)
{
List<int> testList = new List<int>();
for (int i = 0; i < 1000; ++i)
{
testList.Add(1);
}
Console.WriteLine(SubsetSum.Find(testList, 1000));
foreach (int index in SubsetSum.GetLastResult(1000))
{
Console.WriteLine(index);
}
}
}
static class SubsetSum
{
private static Dictionary<int, bool> memo;
private static Dictionary<int, KeyValuePair<int, int>> prev;
static SubsetSum()
{
memo = new Dictionary<int, bool>();
prev = new Dictionary<int, KeyValuePair<int, int>>();
}
public static bool Find(List<int> inputArray, int sum)
{
memo.Clear();
prev.Clear();
memo[0] = true;
prev[0] = new KeyValuePair<int,int>(-1, 0);
for (int i = 0; i < inputArray.Count; ++i)
{
int num = inputArray[i];
for (int s = sum; s >= num; --s)
{
if (memo.ContainsKey(s - num) && memo[s - num] == true)
{
memo[s] = true;
if (!prev.ContainsKey(s))
{
prev[s] = new KeyValuePair<int,int>(i, num);
}
}
}
}
return memo.ContainsKey(sum) && memo[sum];
}
public static IEnumerable<int> GetLastResult(int sum)
{
while (prev[sum].Key != -1)
{
yield return prev[sum].Key;
sum -= prev[sum].Value;
}
}
}
You should do some error checking perhaps, and maybe store the last sum in the class so as not to allow the possibility of calling GetLastResult with a different sum than the sum Find was last called with. Anyway, this is the idea.
Solution 2 - randomized algorithm
Now, this is easier. Keep two lists: usedNums and unusedNums. Also keep a variable usedSum that, at any point in time, contains the sum of all the numbers in the usedNums list.
Whenever you need to insert a number into your set, also add it to one of the two lists (doesn't matter which, but do it randomly so there's a relatively even distribution). Update usedSum accordingly.
Whenever you need to remove a number from your set, find out which of the two lists it's in. You can do this with a linear seach as long as you don't have a lot (this time a lot means over 10 000, maybe even 100 000 on a fast computer and assuming you don't do this operation often and in fast succession. Anyway, the linear search can be optimized if you need it to be.). Once you have found the number, remove it from the list. Update usedSum accordingly.
Whenever you need to find if there are numbers in your set that sum to a number S, use this algorithm:
while S != usedSum
if S > usedSum // our current usedSum is too small
move a random number from unusedNums to usedNums and update usedSum
else // our current usedSum is too big
move a random number from usedNums to unusedNums and update usedSum
At the end of the algorithm, the list usedNums will give you the numbers whose sum is S.
This algorithm should be good for what you need, I think. It handles changes to the dataset very well and works well for a high number count. It also doesn't depend on how big the numbers are, which is very useful if you have big numbers.
Please post if you have any questions.

generating random numbers without repeating with an exception AS3

I have seen this question for other languages but not for AS3... and I'm having a hard time understanding it...
I need to generate 3 numbers, randomly, from 0 to 2, but they cannot repeat (as in 000, 001, 222, 212 etc) and they cannot be in the correct order (0,1,2)...
Im using
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
mcCor.gotoAndStop((Math.random() * (2 - u + 1) + u) | 0); // random w/ repeats
//mcCor.gotoAndStop(Math.floor(Math.random() * (2 - u + 1) + u)); // random w/ repeats
//mcCor.gotoAndStop((Math.random() * 3) | 0); // crap....
//mcCor.gotoAndStop(Math.round(Math.random()*u)); // 1,1,1
//mcCor.gotoAndStop(u + 1); // 1,2,3
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
those are the codes i've been trying.... best one so far is the active one (without the //), but it still gives me duplicates (as 1,1,1) and still has a small chance to come 0,1,2....
BTW, what I want is to mcCor to gotoAndStop on frames 1, 2 or 3....without repeating, so THE USER can put it on the right order (1,2,3 or (u= 0,1,2), thats why I add + 1 sometimes there)
any thoughts?? =)
I've found that one way to ensure random, unique numbers is to store the possible numbers in an array, and then sort them using a "random" sort:
// store the numbers 0, 1, 2 in an array
var sortedNumbers:Array = [];
for(var i:int = 0; i < 3; i++)
{
sortedNumbers.push(i);
}
var unsortedNumbers:Array = sortedNumbers.slice(); // make a copy of the sorted numbers
trace(sortedNumbers); // 0,1,2
trace(unsortedNumbers); // 0,1,2
// randomly sort array until it no longer matches the sorted array
while(sortedNumbers.join() == unsortedNumbers.join())
{
unsortedNumbers.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
trace(unsortedNumbers); // [1,0,2], [2,1,0], [0,1,2], etc
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
// grab the corresponding value from the unsorted array
mcCor.gotoAndStop(unsortedNumbers[u] + 1);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
Marcela is right. Approach with an Array is widely used for such task. Of course, you will need to check 0, 1, 2 sequence and this will be ugly, but in common code to get the random sequence of integers can look like this:
function getRandomSequence(min:int, max:int):Array
{
if (min > max) throw new Error("Max value should be greater than Min value!");
if (min == max) return [min];
var values:Array = [];
for (var i:int = min; i <= max; i++) values.push(i);
var result:Array = [];
while (values.length > 0) result = result.concat(values.splice(Math.floor(Math.random() * values.length), 1));
return result;
}
for (var i:uint = 0; i < 10; i++)
{
trace(getRandomSequence(1, 10));
}
You will get something like that:
2,9,3,8,10,6,5,1,4,7
6,1,2,4,8,9,5,10,7,3
3,9,10,6,8,2,5,4,1,7
7,6,1,4,3,8,9,2,10,5
4,6,7,1,3,2,9,10,8,5
3,10,5,9,1,7,2,4,8,6
1,7,9,6,10,3,4,5,2,8
4,10,8,9,3,2,6,1,7,5
1,7,8,9,10,6,4,3,2,5
7,5,4,2,8,6,10,3,9,1
I created this for you. It is working but it can be optimized...
Hope is good for you.
var arr : Array = [];
var r : int;
for (var i: int = 0; i < 3; i++){
r=rand(0,2);
if(i == 1){
if(arr[0] == r){
i--;
continue;
}
if(arr[0] == 0){
if(r==1){
i--;
continue;
}
}
}else if(i==2){
if(arr[0] == r || arr[1] == r){
i--;
continue;
}
}
arr[i] = r;
}
trace(arr);
for(var i=0;i<3;i++){
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (i % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(i / 3));
mcCor.gotoAndStop(arr[i]);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
function rand(min:int, max:int):int {
return Math.round(Math.random() * (max - min) + min);
}
try this...

How to implement subtraction using only loop and increment

This is an interview question.
We have only two constructs
loop(a) means loop for a times.
increment(a) increments a.
Thus to implement a+b one could write
loop(a) {inc(b)}
return b;
The question is how to implement a-b.
How about;
a = 10
b = 8
result = 0
loop(b) {
last = 0
times = 0;
loop(a) {
last = times
times = inc(times)
}
result = a = last
}
result is 2
Js eg;
var a = 10;
var b = 8;
var result;
for (var _b = 0; _b < b; _b++) {
var last = 0, times = 0, loopa = 0;
for (var _a = 0; _a < a; _a++) {
last = times;
times = inc(times);
}
result = a = last;
}
function inc(i) {
return i + 1;
}
print(result) // 2
I think if break from loop is allowed, a-b can be done in this way:
c=0;
loop(a) {
if (a==b) break;
inc(c);
inc(b);
}
return c;
Ofcourse assuming a>b.
depends if this Numeric architecture is known:
you can take advantage of the "Two Compliment" mechanism of the x86/x64 architecture,
for example, if the signed numbering scheme is cyclic like.
f(0 < x < 32768) = x
f(32769 < x < 65535) = x - 65536
Then you can use:
dec(a)
{
loop(65535 [= 2^16-1]) { inc(a) }
}
.
solving the riddel as
(a-b)
{
loop(b) { dec(a) }
}
Depending on the Signed scheme the addition Constant can change, same for short, long, large integer types.
Hope this is good :)
Best of luck.
We're a looking for x, so that a-b = x. In other words a = b+x
Pseudocode
int x = 0
WHILE (x <= a) do {
if (b+x == a) BREAK // satisfies a-b = x
x++
}
RESET B
INC B
LOOP A
{
INC D
LOOP B
{
RESET D
}
}

Identify the index corresponding to the smallest data in a set of arrays

This is a trivial algorithmic question, I believe, but I don't seem to be able to find an efficient and elegant solution.
We have 3 arrays of int (Aa, Ab, Ac) and 3 cursors (Ca, Cb, Cc) that indicate an index in the corresponding array. I want to identify and increment the cursor pointing to the smallest value. If this cursor is already at the end of the array, I will exclude it and increment the cursor pointing to the second smallest value. If there is only 1 cursor that is not at the end of the array, we increment this one.
The only solutions I can come up are complicated and/or not optimal. For example, I always end up with a huge if...else...
Does anyone see a neat solution to this problem ?
I am programming in C++ but feel free to discuss it in pseudo-code or any language you like.
Thank you
Pseudo-java code:
int[] values = new int[3];
values[0] = aa[ca];
values[1] = ab[cb];
values[2] = ac[cc];
Arrays.sort(values);
boolean done = false;
for (int i = 0; i < 3 && !done; i++) {
if (values[i] == aa[ca] && ca + 1 < aa.length) {
ca++;
done = true;
}
else if (values[i] == ab[cb] && cb + 1 < ab.length) {
cb++;
done = true;
}
else if (cc + 1 < ac.length) {
cc++;
done = true;
}
}
if (!done) {
System.out.println("cannot increment any index");
stop = true;
}
Essentially, it does the following:
initialize an array values with aa[ca], ab[cb] and ac[cc]
sort values
scan values and increment if possible (i.e. not already at the end of the array) the index of the corresponding value
I know, sorting is at best O(n lg n), but I'm only sorting an array of 3 elements.
what about this solution:
if (Ca != arraySize - 1) AND
((Aa[Ca] == min(Aa[Ca], Ab[Cb], Ac[Cc]) OR
(Aa[Ca] == min(Aa[Ca], Ab[Cb]) And Cc == arraySize - 1) OR
(Aa[Ca] == min(Aa[Ca], Ac[Cc]) And Cb == arraySize - 1) OR
(Cc == arraySize - 1 And Cb == arraySize - 1))
{
Ca++;
}
else if (Cb != arraySize - 1) AND
((Ab[Cb] == min(Ab[Cb], Ac[Cc]) OR (Cc == arraySize - 1))
{
Cb++;
}
else if (Cc != arraySize - 1)
{
Cc++;
}
Pseudo code: EDIT : tidied it up a bit
class CursoredArray
{
int index;
std::vector<int> array;
int val()
{
return array[index];
}
bool moveNext()
{
bool ret = true;
if( array.size() > index )
++index;
else
ret = false;
return ret;
}
}
std::vector<CursoredArray> arrays;
std::vector<int> order = { 0, 1, 2 };//have a default order to start with
if( arrays[0].val() > arrays[1].val() )
std::swap( order[0], order [1] );
if( arrays[2].val() < arrays[order[1]].val() )//if the third is less than the largest of the others
{
std::swap( order[1], order [2] );
if( arrays[2].val() < arrays[order[0]].val() )//if the third is less than the smallest of the others
std::swap( order[0], order [1] );
}
//else third pos of order is already correct
bool end = true;
for( i = 0; i < 3; ++i )
{
if( arrays[order[i]].MoveNext() )
{
end = false;
break;
}
}
if( end )//have gone through all the arrays

Resources