I'm implementing the Fiege Fiat Shamir Identification Scheme in Java, and I'm pretty sure that it's fine math-wise. (I've checked many many times) But it never works (when check is called, it is almost always false, even when called with numbers that should work). I've gotten it to work before without sequences, (k value of 1), but now it doesn't work. Help!
public class ZKPTimeTrials {
public static int gcd(int p, int q) {
if (q == 0) return p;
else return gcd(q, p % q);
}
public static int randomR(int min, int max) {
Random randgen = new Random();
return randgen.nextInt((max - min) + 1) + min;
}
public static int getRandomCoprime(int n) {
int result = n;
while (gcd(n, result) != 1) {
result = randomR(2, n-1);
}
return result;
}
public static int[] makeSi(int k, int n) {
int[] result = new int[k];
for(int i = 0; i < result.length; i++) {
result[i] = getRandomCoprime(n);
}
return result;
}
public static int[] makeVi(int[] si, int n) {
int[] result = new int[si.length];
for(int i = 0; i < result.length; i++) {
result[i] = (si[i] * si[i]) % n;
}
return result;
}
public static int[] makeEi(int k) {
int[] result = new int[k];
for(int i = 0; i < k; i++) {
result[i] = randomR(0, 1);
}
return result;
}
public static int makeY(int r, int[] ei, int[] si, int n) {
int result = r;
for(int i = 0; i < si.length; i++) {
result *= (int) Math.pow(si[i], ei[i]);
}
return result % n;
}
public static boolean check(int n, int x, int y, int[] ei, int[] vi) {
int signBit = ZKPTimeTrials.randomR(0, 1);
if(signBit == 0) {
signBit = -1;
}
int shouldY = x * signBit;
for(int i = 0; i < vi.length; i++) {
shouldY *= (int) Math.pow(vi[i], ei[i]);
}
return ((y * y) % n) == shouldY % n;
}
public static void main(String args[]) {
int n = 71 * 7;
int t = 50;
int k = 10;
int[] si = makeSi(k, n);
int[] vi = makeVi(si, n);
int r = randomR(2, n-1);
int ei[] = makeEi(k);
int s = randomR(0, 1);
if(s == 0) {
s = -1;
}
int x = (s * r * r) % n;
int y = makeY(r, ei, si, n);
for(int i = 0; i < si.length; i++) System.out.print(ei[i] + " ");
System.out.println();
for(int i = 0; i < si.length; i++) System.out.print(si[i] + " ");
System.out.println(check(n, x, y, ei, vi));
}
}
The first problem is an integer overflow in makeY and check: In both functions 'result' is very likely to overflow, because you build the product first and reduce modulo n afterwards. Try to reduce mod n after every multiplication to keep 'result' small.
For example in makeY, write:
int result = r % n;
for (int i = 0; i < si.length; i++) {
if (ei[i] == 1)
result = (result * si[i]) % n;
}
return result;
(I also removed Math.pow() to make it more readable and efficient, but this was not an error.)
The second problem is the logic of your check function: The signBit variable is not needed, but instead you should check if y*y is equal to shouldY or -shouldY.
public static boolean check(int n, int x, int y, int[] ei, int[] vi) {
int shouldY = x % n;
for (int i = 0; i < vi.length; i++) {
if (ei[i] == 1)
shouldY = (shouldY * vi[i]) % n;
}
return (y*y - shouldY) % n == 0 || (y*y + shouldY) % n == 0;
}
With these small corrections i managed to get your code running. Hope it helps...
Related
Given a matrix of dimension r*c where each cell in the matrix can have values 0, 1 or 2 which has the following meaning:
0 : Empty cell
1 : Cells have fresh oranges
2 : Cells have rotten oranges
So, we have to determine what is the minimum time required to rot all oranges. A rotten orange at index [i,j] can rot other fresh orange at indexes [i-1,j], [i+1,j], [i,j-1], [i,j+1] (up, down, left and right) in unit time. If it is impossible to rot every orange then simply return -1.
Input:
The first line of input contains an integer T denoting the number of test cases. Each test case contains two integers r and c, where r is the number of rows and c is the number of columns in the array a[]. Next line contains space separated r*c elements each in the array a[].
Here is the Code I have written
class GFG {
public static boolean isSafe(int[][] M, boolean[][] visited, int i, int j) {
int R = M.length;
int C = M[0].length;
return (i >= 0 && i < R && j >= 0 && j < C && (!visited[i][j]) && M[i][j] != 0);
}
public static int findMinDist(int[][] M, boolean[][] visited, int i, int j, int dist) {
if (M[i][j] == 2)
return dist;
int[] x_pos = { 1, -1, 0, 0 };
int[] y_pos = { 0, 0, -1, 1 };
visited[i][j] = true;
int min = Integer.MAX_VALUE;
for (int k = 0; k < 4; k++) {
if (isSafe(M, visited, i + x_pos[k], j + y_pos[k]))
min = Math.min(min, findMinDist(M, visited, i + x_pos[k], j + y_pos[k], dist + 1));
}
return min;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
for (int t = 0; t < T; t++) {
int R = sc.nextInt();
int C = sc.nextInt();
int[][] M = new int[R][C];
boolean[][] visited = new boolean[R][C];
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
M[i][j] = sc.nextInt();
}
}
int[][] time = new int[R][C];
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
if (M[i][j] == 1)
time[i][j] = findMinDist(M, new boolean[R][C], i, j, 0);
}
}
int maxTime = Integer.MIN_VALUE;
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
maxTime = Math.max(time[i][j], maxTime);
}
}
System.out.println(maxTime == Integer.MAX_VALUE ? -1 : maxTime);
}
}
}
I am trying to find minimum distance of 2 from each 1.
It is not working for test case
Input:
1
2 5
1 1 1 1 1 0 2 1 1 1
Its Correct output is:
4
And My Code's output is:
6
Please suggest what's wrong with the code.
Start by creating a matrix to store the times the oranges rot. You can initialize all slots with -1. You will use BFS but you won't need a "marked" matrix, because the times the oranges rot will already be enough to tell you if a slot has been visited or not.
Iterate through the original matrix. When you find a value 2, do a BFS starting there to rot the fresh oranges. This BFS should also state the time when each orange is rot and you must always keep the smallest time. If the orange being looked at the moment was already rotten at time t1 and you've just got there in time t2, where t2 < t1, pretend this orange is fresh and put it into the BFS queue like so.
After finishing it, iterate through the matrix of times and return the biggest value found.
class Pair {
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
public int x;
public int y;
}
public class Solution {
public static boolean isSafe(int x, int y, int r, int c) {
return (x >= 0) && (x < r) && (y >= 0) && (y < c);
}
public static boolean isFreshOrageLeft(int[][] grid) {
int r = grid.length;
int c = grid[0].length;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j] == 1)
return true;
}
}
return false;
}
public static int orangesRotting(int[][] grid) {
int r = grid.length;
int c = grid[0].length;
int count = 0;
boolean flag = false;
Queue<Pair> q = new LinkedList<>();
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j] == 2)
q.add(new Pair(i, j));
}
}
q.add(new Pair(-1, -1));
while (!q.isEmpty()) {
while (q.peek().x != -1 && q.peek().y != -1) {
Pair p = q.poll();
int leftX = p.x - 1;
int leftY = p.y;
if (isSafe(leftX, leftY, r, c) && grid[leftX][leftY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[leftX][leftY] = 2;
q.add(new Pair(leftX, leftY));
}
int rightX = p.x + 1;
int rightY = p.y;
if (isSafe(rightX, rightY, r, c) && grid[rightX][rightY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[rightX][rightY] = 2;
q.add(new Pair(rightX, rightY));
}
int upX = p.x;
int upY = p.y + 1;
if (isSafe(upX, upY, r, c) && grid[upX][upY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[upX][upY] = 2;
q.add(new Pair(upX, upY));
}
int downX = p.x;
int downY = p.y - 1;
if (isSafe(downX, downY, r, c) && grid[downX][downY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[downX][downY] = 2;
q.add(new Pair(downX, downY));
}
}
flag = false;
q.poll();
if (!q.isEmpty())
q.add(new Pair(-1, -1));
}
return isFreshOrageLeft(grid)?-1:count;
}
public static void main(String[] args) {
int[][] grid = {{2,2,0,1}};
System.out.println(orangesRotting(grid));
}
}
What is the simplest way to make a union or an intersection of Sets in Java? I've seen some strange solutions to this simple problem (e.g. manually iterating the two sets).
The simplest one-line solution is this:
set1.addAll(set2); // Union
set1.retainAll(set2); // Intersection
The above solution is destructive, meaning that contents of the original set1 my change.
If you don't want to touch your existing sets, create a new set:
var result = new HashSet<>(set1); // In Java 10 and above
Set<Integer> result = new HashSet<>(set1); // In Java < 10
result.addAll(set2); // Union
result.retainAll(set2); // Intersection
While guava for sure is neater and pretty much standard, here's a non destructive way to do union and intersect using only standard Java
Set s1 = Set.of(1,2,3);
Set s2 = Set.of(3,4,5);
Set union = Stream.concat(s1.stream(),s2.stream()).collect(Collectors.toSet());
Set intersect = s1.stream().filter(s2::contains).collect(Collectors.toSet());
You can achieve this using Google's Guava library. The following explanation is given below with the help of an example:
// Set a
Set<String> a = new HashSet<String>();
a.add("x");
a.add("y");
a.add("z");
// Set b
Set<String> b = new HashSet<String>();
b.add("x");
b.add("p");
b.add("q");
Now, Calculating Intersection of two Set in Java:
Set<String> intersection = Sets.intersection(a, b);
System.out.printf("Intersection of two Set %s and %s in Java is %s %n",
a.toString(), b.toString(), intersection.toString());
Output: Intersection of two Set [z, y, x] and [q, p, x] in Java is [x]
Similarly, Calculating Union of two Set in Java:
Set<String> union = Sets.union(a, b);
System.out.printf("Union of two Set %s and %s in Java is %s %n",
a.toString(), b.toString(), union.toString());
Output: Union of two Set [z, y, x] and [q, p, x] in Java is [q, p, x, z, y]
You can read more about guava library at https://google.github.io/guava/releases/18.0/api/docs/
In order to add guava library to your project, You can see https://stackoverflow.com/a/4648947/8258942
import java.util.*;
public class sets {
public static void swap(int array[], int a, int b) { // Swap function for sorting
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
public static int[] sort(int array[]) { // sort function for binary search (Selection sort)
int minIndex;
int j;
for (int i = 0; i < array.length; i++) {
minIndex = i;
for (j = i + 1; j < array.length; j++) {
if (array[minIndex] > array[j])
minIndex = j;
}
swap(array, minIndex, i);
}
return array;
}
public static boolean search(int array[], int search) { // Binary search for intersection and difference
int l = array.length;
int mid = 0;
int lowerLimit = 0, upperLimit = l - 1;
while (lowerLimit <= upperLimit) {
mid = (lowerLimit + upperLimit) / 2;
if (array[mid] == search) {
return true;
} else if (array[mid] > search)
upperLimit = mid - 1;
else if (array[mid] < search)
lowerLimit = mid + 1;
}
return false;
}
public static int[] append(int array[], int add) { // To add elements
int newArray[] = new int[array.length + 1];
for (int i = 0; i < array.length; i++) {
newArray[i] = array[i];
}
newArray[array.length] = add;
newArray = sort(newArray);
return newArray;
}
public static int[] remove(int array[], int index) { // To remove duplicates
int anotherArray[] = new int[array.length - 1];
int k = 0;
if (array == null || index < 0 || index > array.length) {
return array;
}
for (int i = 0; i < array.length; i++) {
if (index == i) {
continue;
}
anotherArray[k++] = array[i];
}
return anotherArray;
}
public static void Union(int A[], int B[]) { // Union of a set
int union[] = new int[A.length + B.length];
for (int i = 0; i < A.length; i++) {
union[i] = A[i];
}
for (int j = A.length, i = 0; i < B.length || j < union.length; i++, j++) {
union[j] = B[i];
}
for (int i = 0; i < union.length; i++) {
for (int j = 0; j < union.length; j++) {
if (union[i] == union[j] && j != i) {
union = remove(union, j); // Removing duplicates
}
}
}
union = sort(union);
System.out.print("A U B = {"); // Printing
for (int i = 0; i < union.length; i++) {
if (i != union.length - 1)
System.out.print(union[i] + ", ");
else
System.out.print(union[i] + "}");
}
}
public static void Intersection(int A[], int B[]) {
int greater = (A.length > B.length) ? (A.length) : (B.length);
int intersect[] = new int[1];
int G[] = (A.length > B.length) ? A : B;
int L[] = (A.length < B.length) ? A : B;
for (int i = 0; i < greater; i++) {
if (search(L, G[i]) == true) { // Common elements
intersect = append(intersect, G[i]);
}
}
for (int i = 0; i < intersect.length; i++) {
for (int j = 0; j < intersect.length; j++) {
if (intersect[i] == intersect[j] && j != i) {
intersect = remove(intersect, j); // Removing duplicates
}
}
}
System.out.print("A ∩ B = {"); // Printing
for (int i = 1; i < intersect.length; i++) {
if (i != intersect.length - 1)
System.out.print(intersect[i] + ", ");
else
System.out.print(intersect[i] + "}");
}
}
public static void difference(int A[], int B[]) {
int diff[] = new int[1];
int G[] = (A.length > B.length) ? A : B;
int L[] = (A.length < B.length) ? A : B;
int greater = G.length;
for (int i = 0; i < greater; i++) {
if (search(L, G[i]) == false) {
diff = append(diff, G[i]); // Elements not in common
}
}
for (int i = 0; i < diff.length; i++) {
for (int j = 0; j < diff.length; j++) {
if (diff[i] == diff[j] && j != i) {
diff = remove(diff, j); // Removing duplicates
}
}
}
System.out.println("Where A is the larger set, and B is the smaller set.");
System.out.print("A - B = {"); // Printing
for (int i = 1; i < diff.length; i++) {
if (i != diff.length - 1)
System.out.print(diff[i] + ", ");
else
System.out.print(diff[i] + "}");
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the operation");
String operation = sc.next().toLowerCase();
System.out.println("Enter the length of the first set.");
int l1 = sc.nextInt();
System.out.println("Enter the length of the second set.");
int l2 = sc.nextInt();
int A[] = new int[l1];
int B[] = new int[l2];
System.out.println("Enter the elements of the first set.");
System.out.print("A = ");
for (int i = 0; i < l1; i++) {
A[i] = sc.nextInt();
}
System.out.println("Enter the elements of the second set.");
System.out.print("B = ");
for (int i = 0; i < l2; i++) {
B[i] = sc.nextInt();
}
A = sort(A); // Sorting the sets before passing
B = sort(B);
sc.close();
switch (operation) {
case "union":
Union(A, B);
break;
case "intersection":
Intersection(A, B);
break;
case "difference":
difference(B, A);
break;
default:
System.out.println("Invalid Operation");
}
}
}
When I think of union and intersection, it is in the first loop an operation on sets, i.e. a map
Set<T> x Set<T> → Set<T>Not clear, why it would appear in Java design that shirtsleeved.
static <T> Set<T> union(Set<T> a, Set<T> b)
{
Set<T> res = new HashSet<T>(a);
res.addAll(b);
return res;
}
static <T> Set<T> intersection(Set<T> a, Set<T> b)
{
Set<T> res = new HashSet<T>(a);
res.retainAll(b);
return res;
}
I have implemented a chain matrix multiplication. Although I get correct chain order, but while doing actual multiplication, the given multiply algorithm is not working properly. My Java Code:-
package algopackage;
import java.util.ArrayList;
import java.util.List;
public class ChainMatrixMultiplication {
static int s[][];
static int x[][];
static int y[][];
public ChainMatrixMultiplication() {
}
static void chainMatrixMultiplication(int[] p) {
boolean isFirst = false;
int n = p.length-1;
int m[][] = new int[n][n];
s = new int[n][n];
for (int c = 0; c < n; c++)
m[c][c] = 0;
for (int counter = 1; counter < n; counter++) {
for (int i = 0;i < n; i++) {
isFirst = false;
int j = i + counter;
for (int k = i; k < j && j < n; k++) {
int result = m[i][k] + m[k+1][j] + p[i] * p[k+1] * p[j+1];
if (!isFirst) {
m[i][j] = result;
s[i][j] = k;
isFirst = true;
} else if (m[i][j] > result) {
m[i][j] = result;
s[i][j] = k;
}
}
}
}
}
static int[][] matrixMultiply(List<Matrix> matrices, int s[][], int i ,int j) {
if (i ==j) return matrices.get(i).getMatrix();
else {
int k = s[i][j];
x = matrixMultiply(matrices, s, i, k);
y = matrixMultiply(matrices, s, k+1, j);
return mult(x,y);
}
}
static int[][] mult(int[][] x, int[][] y) {
int [][] result = new int[x.length][y[0].length];
/* Loop through each and get product, then sum up and store the value */
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < y[0].length; j++) {
for (int k = 0; k < x[0].length; k++) {
result[i][j] += x[i][k] * y[k][j];
}
}
}
return result;
}
public static void main(String[] args) {
int p[] = {5,4,6,2};
List<Matrix> matrices = new ArrayList<Matrix>();
Matrix m1 = new Matrix(5,4);
int arr[] = {1,2,40,2,3,29,10,21,11,120,23,90,24,12,11,1,11,45,23,21};
m1.addElementsToMatrix(5, 4, arr);
Matrix m2 = new Matrix(4,6);
int arr1[] = {1,1,1,2,3,12,12,3,10,12,12,29,22,11,22,11,11,11,13,1,2,12,4,2};
m2.addElementsToMatrix(4, 6, arr1);
Matrix m3 = new Matrix(6,2);
int arr2[] = {1,1,12,3,22,11,13,1,2,12,12,12};
m3.addElementsToMatrix(6, 2, arr2);
matrices.add(m1);
matrices.add(m2);
matrices.add(m3);
chainMatrixMultiplication(p);
matrixMultiply(matrices,s,0,2);
}
}
class Matrix {
private final int[][] matrix;
public Matrix(int rows, int cols) {
this.matrix = new int[rows][cols];
}
public void addElementsToMatrix(int rows, int cols, int[] arr) {
int counter = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = arr[counter++];
}
}
}
public int[][] getMatrix() {
return matrix;
}
}
In the above code matrixMultiply() function is throwing exception. Exception is caused as matrices are not being multiplied as expected. As recursion is not behaving as expected. I am missing something in this code. Any help will be appreciated.Thanks!
I'm not sure of the correctness of your code, but looking at the matrix multiplication output when you multiply matrix of dimension a*b and c*d after you multiply, you get a matrix of dimension a*d there by changing
for (int k = 0; k < x[0].length; k++) {
to
for (int k = 0; k < y[0].length; k++) {
should resolve the problem.
This:
x = matrixMultiply(matrices, s, i, k); // call A
y = matrixMultiply(matrices, s, k+1, j); // call B
return mult(x,y);
looks like it should multiply the result of call A by the result of call B. But in general, it doesn't.
x is not local, call B will usually overwrite it, except when call B immediately hits the base case.
This sort of thing tends to happen when you pass data around "to the side", not as function parameter or function return value. It is not reasonable to avoid that kind of data flow all the time, but you should avoid it here, especially since it's not even what you wanted.
I'm trying to implement memoized version of recursive rod cutting algorithm. Here is my code (I implemented it from Cormen's pseudo code)
public class simpleMemoized {
//finds maximum of two given integers
public static int max(int a, int b) {
return (a > b) ? a : b;
}
public static int MemoizedCutRod(int price, int lenght) {
int[] r = new int[lenght + 1];
for (int i = 1; i <= lenght; i++) {
r[i] = 0;
}
return MemoizedCutRodAux(price, lenght, r);
}
public static int MemoizedCutRodAux(int price, int lenght, int[] r) {
int[] priceTable = new int[11];
priceTable[1] = 1;
priceTable[2] = 5;
priceTable[3] = 8;
priceTable[4] = 9;
priceTable[5] = 10;
priceTable[6] = 17;
priceTable[7] = 17;
priceTable[8] = 20;
priceTable[9] = 24;
priceTable[10] = 30;
if (r[lenght] >= 0) {
return r[lenght];
}
if (lenght == 0) {
return 0;
}
int q = 0;
for (int i = 1; i <= lenght; i++) {
q = max(q, priceTable[i] + MemoizedCutRodAux(price, lenght, r));
r[lenght] = q;
}
return q;
}
All outputs of this code are 0. But non memorized version of this code is working. What is the problem with it? Here is the working code:
public class Simple {
//finds maximum of two given integers
public static int max(int a, int b) {
return (a > b) ? a : b;
}
public static int cormenCutRod(int price, int lenght) {
int[] priceTable = new int[11];
priceTable[1] = 1;
priceTable[2] = 5;
priceTable[3] = 8;
priceTable[4] = 9;
priceTable[5] = 10;
priceTable[6] = 17;
priceTable[7] = 17;
priceTable[8] = 20;
priceTable[9] = 24;
priceTable[10] = 30;
if (lenght == 0) {
return 0;
}
int q = 0;
for (int i = 1; i <= lenght; i++) {
q = max(q, priceTable[i] + cormenCutRod(price, lenght - i));
}
return q;
}
This should work.
static int cutRodM(int lenght)
{
int[] priceTable = new int[11];
priceTable[1] = 1;
priceTable[2] = 5;
priceTable[3] = 8;
priceTable[4] = 9;
priceTable[5] = 10;
priceTable[6] = 17;
priceTable[7] = 17;
priceTable[8] = 20;
priceTable[9] = 24;
priceTable[10] = 30;
int[] mem= new int[lenght+1];
mem[0] = 0;
int i, j;
//filling the table bottom up
for (i = 1; i<=lenght; i++)
{
int q = 0;
for (j = 1; j <= i; j++)
q = max(q, priceTable[j] + mem[i-j]);
mem[i] = q;
}
return mem[lenght];
}
Ideone link: http://ideone.com/OWgrAZ
I've spent quite a while working on Problem #23 on Project Euler.
The answer the program below gives me is 4190428, and I can't figure out why.
I think it's probably a one or two character mistake somewhere.
public long problem23() {
ArrayList<Integer> abundantNumbers = new ArrayList<Integer>();
int limit = 28123;
for(int i = 2; i < limit; i++) {
if(isAbundantNum(i)) {
abundantNumbers.add(i);
}
}
boolean [] abundantSum = new boolean [limit+1];
for(int a = 0; a < abundantNumbers.size(); a++) {
for(int b = 1; b < abundantNumbers.size(); b++) {
int temp = abundantNumbers.get(a) + abundantNumbers.get(b);
if(temp <= limit) {
abundantSum[temp] = true;
} else {
break;
}
}
}
long sum = 0;
for(int i = 1; i <= limit; i++) {
if(!abundantSum[i]) {
sum += i;
}
}
return sum;
}
public boolean isAbundantNum(int n) {
int factorSum = 1;
for(int i = 2; i < Math.sqrt(n); i++) {
if(n%i == 0) {
factorSum += i; factorSum += n/i;
}
}
if(factorSum > n) {
System.out.println(n);
return true;
}
return false;
}
Edit: Added isAbundantNum(int n) method.
You have 2 bugs...
for(int b = 1; b < abundantNumbers.size(); b++) {
'b' should start at zero not 1
for(int i = 2; i < Math.sqrt(n); i++) {
if(n%i == 0) {
factorSum += i; factorSum += n/i;
}
}
Factoring like that gives you duplicates (like 2*2 = 4, you're getting both 2s).
Try something like:
for(int i = 2; i < n; i++) {
if(n%i == 0) {
factorSum += i;
}
}
Here is another implementation:
import java.util.ArrayList;
import java.util.List;
public class P23 {
final static int MIN = 12;
final static int MAX = 28123;
static boolean numbers[] = new boolean[MAX+1];
static List<Integer> abundantNumbers = new ArrayList();
public static void main(String args[]) {
generateAbundants(MIN, MAX);
int size = abundantNumbers.size();
for (int i = 0; i < size; i++) {
for (int j = i; j < size; j++) {
int current = abundantNumbers.get(i) + abundantNumbers.get(j);
if (current <= MAX) {
numbers[current] = true;
} else {
break;
}
}
}
long sum = 0;
for (int i = 1 ; i <= MAX ; i++ ) {
if ( numbers[i] == false ) {
sum += i;
}
}
System.out.println(sum);
}
private static int sumOfProperDivisors(int x) {
int sum = 1;
int squareRoot = (int) Math.sqrt(x);
for (int i = 2; i <= squareRoot; i++) {
if (x % i == 0) {
sum += i;
sum += x / i;
}
}
// if x is a perfect square, it's square root was added twice
if (squareRoot * squareRoot == x) {
sum -= squareRoot;
}
return sum;
}
private static boolean isAbundant(int x) {
if (x < sumOfProperDivisors(x)) {
return true;
}
return false;
}
private static void generateAbundants(int min, int max) {
for (int i = min; i < max; i++) {
if (isAbundant(i)) {
abundantNumbers.add(i);
}
}
}
}
Time: 455 ms
Explanation:
The default value for j is i. You can take j = 0 ( as Ted Bigham said -> b in that case ), because it will work, but it will take into consideration every number twice ( 12+20 = 20+12 ). It's more efficient to start from i. Why isn't it good to start from 1? Because you can loose solutions: in my example 24 = 12 + 12.
Regarding the for loop containing the divisors part, you can use the approach containing sqrt because it's more efficient ( O(sqrt(n)) instead of O(n) ), but you have to adjust it. In my example you can see that I have <= squareRoot because if I don't use =, it will skip some values ( E.g.: 6 is divisor for 36, but you don't include it in your solution ). Because I counted 6 twice, I remove one of those roots. Of course that Ted's method is good, but sometimes it's better to have an improved performance, even if the simplicity is affected.