Related
I am trying to attempt this leetcode quesstion, but i keep getting Runtime exceeded. Please help :
The Question is :
You are given an n x n integer matrix grid where each value grid[i][j] represents the elevation at that point (i, j).
The rain starts to fall. At time t, the depth of the water everywhere is t. You can swim from a square to another 4-directionally adjacent square if and only if the elevation of both squares individually are at most t. You can swim infinite distances in zero time. Of course, you must stay within the boundaries of the grid during your swim.
Return the least time until you can reach the bottom right square (n - 1, n - 1) if you start at the top left square (0, 0).
link:https://leetcode.com/problems/swim-in-rising-water/
my code
class Solution {
public int swimInWater(int[][] grid) {
PriorityQueue<int[]> pq=new PriorityQueue<>((a,b)->a[2]-b[2]);
pq.add(new int[]{0,0,0});
int count=0;
HashSet<int[]>set=new HashSet<>();
while(!pq.isEmpty())
{
int[] arr=pq.poll();
// System.out.println(set);
if(set.contains(new int[]{arr[0],arr[1]}))
continue;
set.add(new int[]{arr[0],arr[1]});
count=Math.max(count,arr[2]);
if(arr[0]==grid.length-1 && arr[1]==grid[0].length-1)
return count;
if(isvalid(arr[0]+1,arr[1],set,grid))
pq.add(new int[]{arr[0]+1,arr[1],grid[arr[0]+1][arr[1]]});
if(isvalid(arr[0]-1,arr[1],set,grid))
pq.add(new int[]{arr[0]-1,arr[1],grid[arr[0]-1][arr[1]]});
if(isvalid(arr[0],arr[1]+1,set,grid))
pq.add(new int[]{arr[0],arr[1]+1,grid[arr[0]][arr[1]+1]});
if(isvalid(arr[0],arr[1]-1,set,grid))
pq.add(new int[]{arr[0],arr[1]-1,grid[arr[0]][arr[1]-1]});
}
return count;
}
public boolean isvalid(int i, int j , HashSet<int[]> set,int[][] grid)
{
if(i<0 || j<0 || i==grid.length || j==grid[0].length || set.contains(new int[] {i,j}))
return false;
return true;
}
}
I am given 2 arrays, Input and Output Array. The goal is to transform the input array to output array by performing shifting of 1 value in a given step to its adjacent element. Eg: Input array is [0,0,8,0,0] and Output array is [2,0,4,0,2]. Here 1st step would be [0,1,7,0,0] and 2nd step would be [0,1,6,1,0] and so on.
What can be the algorithm to do this efficiently? I was thinking of performing BFS but then we have to do BFS from each element and this can be exponential. Can anyone suggest solution for this problem?
I think you can do this simply by scanning in each direction tracking the cumulative value (in that direction) in the current array and the desired output array and pushing values along ahead of you as necessary:
scan from the left looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the right
scan from the right looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the left
For your example the steps would be:
FWD:
[0,0,8,0,0]
[0,0,7,1,0]
[0,0,6,2,0]
[0,0,6,1,1]
[0,0,6,0,2]
REV:
[0,1,5,0,2]
[0,2,4,0,2]
[1,1,4,0,2]
[2,0,4,0,2]
i think BFS could actually work.
notice that n*O(n+m) = O(n^2+nm) and therefore not exponential.
also you could use: Floyd-Warshall algorithm and Johnson’s algorithm, with a weight of 1 for a "flat" graph, or even connect the vertices in a new way by their actual distance and potentially save some iterations.
hope it helped :)
void transform(int[] in, int[] out, int size)
{
int[] state = in.clone();
report(state);
while (true)
{
int minPressure = 0;
int indexOfMinPressure = 0;
int maxPressure = 0;
int indexOfMaxPressure = 0;
int pressureSum = 0;
for (int index = 0; index < size - 1; ++index)
{
int lhsDiff = state[index] - out[index];
int rhsDiff = state[index + 1] - out[index + 1];
int pressure = lhsDiff - rhsDiff;
if (pressure < minPressure)
{
minPressure = pressure;
indexOfMinPressure = index;
}
if (pressure > maxPressure)
{
maxPressure = pressure;
indexOfMaxPressure = index;
}
pressureSum += pressure;
}
if (minPressure == 0 && maxPressure == 0)
{
break;
}
boolean shiftLeft;
if (Math.abs(minPressure) > Math.abs(maxPressure))
{
shiftLeft = true;
}
else if (Math.abs(minPressure) < Math.abs(maxPressure))
{
shiftLeft = false;
}
else
{
shiftLeft = (pressureSum < 0);
}
if (shiftLeft)
{
++state[indexOfMinPressure];
--state[indexOfMinPressure + 1];
}
else
{
--state[indexOfMaxPressure];
++state[indexOfMaxPressure + 1];
}
report(state);
}
}
A simple greedy algorithm will work and do the job in minimum number of steps. The function returns the total numbers of steps required for the task.
int shift(std::vector<int>& a,std::vector<int>& b){
int n = a.size();
int sum1=0,sum2=0;
for (int i = 0; i < n; ++i){
sum1+=a[i];
sum2+=b[i];
}
if (sum1!=sum2)
{
return -1;
}
int operations=0;
int j=0;
for (int i = 0; i < n;)
{
if (a[i]<b[i])
{
while(j<n and a[j]==0){
j++;
}
if(a[j]<b[i]-a[i]){
operations+=(j-i)*a[j];
a[i]+=a[j];
a[j]=0;
}else{
operations+=(j-i)*(b[i]-a[i]);
a[j]-=(b[i]-a[i]);
a[i]=b[i];
}
}else if (a[i]>b[i])
{
a[i+1]+=(a[i]-b[i]);
operations+=(a[i]-b[i]);
a[i]=b[i];
}else{
i++;
}
}
return operations;
}
Here -1 is a special value meaning that given array cannot be converted to desired one.
Time Complexity: O(n).
I have an array that I would like to iterate in random order. That is, I would like my iteration to visit each element only once in a seemingly random order.
Would it be possible to implement an iterator that would iterate elements like this without storing the order or other data in a lookup table first?
Would it be possible to do it for N-dimensional arrays where N>1?
UPDATE: Some of the answers mention how to do this by storing indices. A major point of this question is how to do it without storing indices or other data.
I decided to solve this, because it annoyed me to death not remembering the name of solution that I had heard before. I did however remember in the end, more on that in the bottom of this post.
My solution depends on the mathematical properties of some cleverly calculated numbers
range = array size
prime = closestPrimeAfter(range)
root = closestPrimitiveRootTo(range/2)
state = root
With this setup we can calculate the following repeatedly and it will iterate all elements of the array exactly once in a seemingly random order, after which it will loop to traverse the array in the same exact order again.
state = (state * root) % prime
I implemented and tested this in Java, so I decided to paste my code here for future reference.
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class PseudoRandomSequence {
private long state;
private final long range;
private final long root;
private final long prime;
//Debugging counter
private int dropped = 0;
public PseudoRandomSequence(int r) {
range = r;
prime = closestPrimeAfter(range);
root = modPow(generator(prime), closestPrimeTo(prime / 2), prime);
reset();
System.out.println("-- r:" + range);
System.out.println(" p:" + prime);
System.out.println(" k:" + root);
System.out.println(" s:" + state);
}
// https://en.wikipedia.org/wiki/Primitive_root_modulo_n
private static long modPow(long base, long exp, long mod) {
return BigInteger.valueOf(base).modPow(BigInteger.valueOf(exp), BigInteger.valueOf(mod)).intValue();
}
//http://e-maxx-eng.github.io/algebra/primitive-root.html
private static long generator(long p) {
ArrayList<Long> fact = new ArrayList<Long>();
long phi = p - 1, n = phi;
for (long i = 2; i * i <= n; ++i) {
if (n % i == 0) {
fact.add(i);
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) fact.add(n);
for (long res = 2; res <= p; ++res) {
boolean ok = true;
for (long i = 0; i < fact.size() && ok; ++i) {
ok &= modPow(res, phi / fact.get((int) i), p) != 1;
}
if (ok) {
return res;
}
}
return -1;
}
public long get() {
return state - 1;
}
public void advance() {
//This loop simply skips all results that overshoot the range, which should never happen if range is a prime number.
dropped--;
do {
state = (state * root) % prime;
dropped++;
} while (state > range);
}
public void reset() {
state = root;
dropped = 0;
}
private static boolean isPrime(long num) {
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0) return false;
}
return true;
}
private static long closestPrimeAfter(long n) {
long up;
for (up = n + 1; !isPrime(up); ++up)
;
return up;
}
private static long closestPrimeBefore(long n) {
long dn;
for (dn = n - 1; !isPrime(dn); --dn)
;
return dn;
}
private static long closestPrimeTo(long n) {
final long dn = closestPrimeBefore(n);
final long up = closestPrimeAfter(n);
return (n - dn) > (up - n) ? up : dn;
}
private static boolean test(int r, int loops) {
final int array[] = new int[r];
Arrays.fill(array, 0);
System.out.println("TESTING: array size: " + r + ", loops: " + loops + "\n");
PseudoRandomSequence prs = new PseudoRandomSequence(r);
final long ct = loops * r;
//Iterate the array 'loops' times, incrementing the value for each cell for every visit.
for (int i = 0; i < ct; ++i) {
prs.advance();
final long index = prs.get();
array[(int) index]++;
}
//Verify that each cell was visited exactly 'loops' times, confirming the validity of the sequence
for (int i = 0; i < r; ++i) {
final int c = array[i];
if (loops != c) {
System.err.println("ERROR: array element #" + i + " was " + c + " instead of " + loops + " as expected\n");
return false;
}
}
//TODO: Verify the "randomness" of the sequence
System.out.println("OK: Sequence checked out with " + prs.dropped + " drops (" + prs.dropped / loops + " per loop vs. diff " + (prs.prime - r) + ") \n");
return true;
}
//Run lots of random tests
public static void main(String[] args) {
Random r = new Random();
r.setSeed(1337);
for (int i = 0; i < 100; ++i) {
PseudoRandomSequence.test(r.nextInt(1000000) + 1, r.nextInt(9) + 1);
}
}
}
As stated in the top, about 10 minutes after spending a good part of my night actually getting a result, I DID remember where I had read about the original way of doing this. It was in a small C implementation of a 2D graphics "dissolve" effect as described in Graphics Gems vol. 1 which in turn is an adaption to 2D with some optimizations of a mechanism called "LFSR" (wikipedia article here, original dissolve.c source code here).
You could collect all possible indices in a list and then remove a random indece to visit. I know this is sort of like a lookup table, but i don't see any other option than this.
Here is an example for a one-dimensional array (adaption to multiple dimensions should be trivial):
class RandomIterator<T> {
T[] array;
List<Integer> remainingIndeces;
public RandomIterator(T[] array) {
this.array = array;
this.remainingIndeces = new ArrayList<>();
for(int i = 0;i<array.length;++i)
remainingIndeces.add(i);
}
public T next() {
return array[remainingIndeces.remove((int)(Math.random()*remainingIndeces.size()))];
}
public boolean hasNext() {
return !remainingIndeces.isEmpty();
}
}
On a side note: If this code is performance relevant, this method would perform worse by far, as the random removing from the list triggers copies if you use a list backed by an array (a linked-list won't help either, as indexed access is O(n)). I would suggest a lookup-structure (e.g. HashSet in Java) that stores all visited indices to circumvent this problem (though that's exactly what you did not want to use)
EDIT: Another approach is to copy said array and use a library function to shuffle it and then traverse it in linear order. If your array isn't that big, this seems like the most readable and performant option.
You would need to create a pseudo random number generator that generates values from 0 to X-1 and takes X iterations before repeating the cycle, where X is the product of all the dimension sizes. I don't know if there is a generic solution to doing this. Wiki article for one type of random number generator:
http://en.wikipedia.org/wiki/Linear_congruential_generator
Yes, it is possible. Imagine 3D array (you not likely use anything more than that). This is like a cube and where all 3 lines connect is a cell. You can enumerate your cells 1 to N using a dictionary, you can do this initialization in loops, and create a list of cells to use for random draw
Initialization
totalCells = ... (xMax * yMax * zMax)
index = 0
For (x = 0; x < xMax ; x++)
{
For (y = 0; y < yMax ; y++)
{
For (z = 0; z < zMax ; z++)
{
dict.Add(i, new Cell(x, y, z))
lst.Add(i)
i++
}
}
}
Now, all you have to do is iterate randomly
Do While (lst.Count > 0)
{
indexToVisit = rand.Next(0, lst.Count - 1)
currentCell = dict[lst[indexToVisit]]
lst.Remove(indexToVisit)
// Do something with current cell here
. . . . . .
}
This is pseudo code, since you didn't mention language you work in
Another way is to randomize 3 (or whatever number of dimensions you have) lists and then just nested loop through them - this will be random in the end.
I was doing this course on algorithms from MIT. In the very first lecture the professor presents the following problem:-
A peak in a 2D array is a value such that all it's 4 neighbours are less than or equal to it, ie. for
a[i][j] to be a local maximum,
a[i+1][j] <= a[i][j]
&& a[i-1][j] <= a[i][j]
&& a[i][j+1] <= a[i][j]
&& a[i+1][j-1] <= a[i][j]
Now given an NxN 2D array, find a peak in the array.
This question can be easily solved in O(N^2) time by iterating over all the elements and returning a peak.
However it can be optimized to be solved in O(NlogN) time by using a divide and conquer solution as explained here.
But they have said that there exists an O(N) time algorithm that solves this problem. Please suggest how can we solve this problem in O(N) time.
PS(For those who know python) The course staff has explained an approach here (Problem 1-5. Peak-Finding Proof) and also provided some python code in their problem sets. But the approach explained is totally non-obvious and very hard to decipher. The python code is equally confusing. So I have copied the main part of the code below for those who know python and can tell what algorithm is being used from the code.
def algorithm4(problem, bestSeen = None, rowSplit = True, trace = None):
# if it's empty, we're done
if problem.numRow <= 0 or problem.numCol <= 0:
return None
subproblems = []
divider = []
if rowSplit:
# the recursive subproblem will involve half the number of rows
mid = problem.numRow // 2
# information about the two subproblems
(subStartR1, subNumR1) = (0, mid)
(subStartR2, subNumR2) = (mid + 1, problem.numRow - (mid + 1))
(subStartC, subNumC) = (0, problem.numCol)
subproblems.append((subStartR1, subStartC, subNumR1, subNumC))
subproblems.append((subStartR2, subStartC, subNumR2, subNumC))
# get a list of all locations in the dividing column
divider = crossProduct([mid], range(problem.numCol))
else:
# the recursive subproblem will involve half the number of columns
mid = problem.numCol // 2
# information about the two subproblems
(subStartR, subNumR) = (0, problem.numRow)
(subStartC1, subNumC1) = (0, mid)
(subStartC2, subNumC2) = (mid + 1, problem.numCol - (mid + 1))
subproblems.append((subStartR, subStartC1, subNumR, subNumC1))
subproblems.append((subStartR, subStartC2, subNumR, subNumC2))
# get a list of all locations in the dividing column
divider = crossProduct(range(problem.numRow), [mid])
# find the maximum in the dividing row or column
bestLoc = problem.getMaximum(divider, trace)
neighbor = problem.getBetterNeighbor(bestLoc, trace)
# update the best we've seen so far based on this new maximum
if bestSeen is None or problem.get(neighbor) > problem.get(bestSeen):
bestSeen = neighbor
if not trace is None: trace.setBestSeen(bestSeen)
# return when we know we've found a peak
if neighbor == bestLoc and problem.get(bestLoc) >= problem.get(bestSeen):
if not trace is None: trace.foundPeak(bestLoc)
return bestLoc
# figure out which subproblem contains the largest number we've seen so
# far, and recurse, alternating between splitting on rows and splitting
# on columns
sub = problem.getSubproblemContaining(subproblems, bestSeen)
newBest = sub.getLocationInSelf(problem, bestSeen)
if not trace is None: trace.setProblemDimensions(sub)
result = algorithm4(sub, newBest, not rowSplit, trace)
return problem.getLocationInSelf(sub, result)
#Helper Method
def crossProduct(list1, list2):
"""
Returns all pairs with one item from the first list and one item from
the second list. (Cartesian product of the two lists.)
The code is equivalent to the following list comprehension:
return [(a, b) for a in list1 for b in list2]
but for easier reading and analysis, we have included more explicit code.
"""
answer = []
for a in list1:
for b in list2:
answer.append ((a, b))
return answer
Let's assume that width of the array is bigger than height, otherwise we will split in another direction.
Split the array into three parts: central column, left side and right side.
Go through the central column and two neighbour columns and look for maximum.
If it's in the central column - this is our peak
If it's in the left side, run this algorithm on subarray left_side + central_column
If it's in the right side, run this algorithm on subarray right_side + central_column
Why this works:
For cases where the maximum element is in the central column - obvious. If it's not, we can step from that maximum to increasing elements and will definitely not cross the central row, so a peak will definitely exist in the corresponding half.
Why this is O(n):
step #3 takes less than or equal to max_dimension iterations and max_dimension at least halves on every two algorithm steps. This gives n+n/2+n/4+... which is O(n). Important detail: we split by the maximum direction. For square arrays this means that split directions will be alternating. This is a difference from the last attempt in the PDF you linked to.
A note: I'm not sure if it exactly matches the algorithm in the code you gave, it may or may not be a different approach.
To see thata(n):
Calculation step is in the picture
To see algorithm implementation:
1) start with either 1a) or 1b)
1a) set left half, divider, right half.
1b) set top half, divider, bottom half.
2) Find global maximum on the divider. [theta n]
3) Find the values of its neighbour. And record the largest node ever visited as the bestSeen node. [theta 1]
# update the best we've seen so far based on this new maximum
if bestSeen is None or problem.get(neighbor) > problem.get(bestSeen):
bestSeen = neighbor
if not trace is None: trace.setBestSeen(bestSeen)
4) check if the global maximum is larger than the bestSeen and its neighbour.
[theta 1]
//Step 4 is the main key of why this algorithm works
# return when we know we've found a peak
if neighbor == bestLoc and problem.get(bestLoc) >= problem.get(bestSeen):
if not trace is None: trace.foundPeak(bestLoc)
return bestLoc
5) If 4) is True, return the global maximum as 2-D peak.
Else if this time did 1a), choose the half of BestSeen, go back to step 1b)
Else, choose the half of BestSeen, go back to step 1a)
To see visually why this algorithm works, it is like grabbing the greatest value side, keep reducing the boundaries and eventually get the BestSeen value.
# Visualised simulation
round1
round2
round3
round4
round5
round6
finally
For this 10*10 matrix, we used only 6 steps to search for the 2-D peak, its quite convincing that it is indeed theta n
By Falcon
Here is the working Java code that implements #maxim1000 's algorithm. The following code finds a peak in the 2D array in linear time.
import java.util.*;
class Ideone{
public static void main (String[] args) throws java.lang.Exception{
new Ideone().run();
}
int N , M ;
void run(){
N = 1000;
M = 100;
// arr is a random NxM array
int[][] arr = randomArray();
long start = System.currentTimeMillis();
// for(int i=0; i<N; i++){ // TO print the array.
// System. out.println(Arrays.toString(arr[i]));
// }
System.out.println(findPeakLinearTime(arr));
long end = System.currentTimeMillis();
System.out.println("time taken : " + (end-start));
}
int findPeakLinearTime(int[][] arr){
int rows = arr.length;
int cols = arr[0].length;
return kthLinearColumn(arr, 0, cols-1, 0, rows-1);
}
// helper function that splits on the middle Column
int kthLinearColumn(int[][] arr, int loCol, int hiCol, int loRow, int hiRow){
if(loCol==hiCol){
int max = arr[loRow][loCol];
int foundRow = loRow;
for(int row = loRow; row<=hiRow; row++){
if(max < arr[row][loCol]){
max = arr[row][loCol];
foundRow = row;
}
}
if(!correctPeak(arr, foundRow, loCol)){
System.out.println("THIS PEAK IS WRONG");
}
return max;
}
int midCol = (loCol+hiCol)/2;
int max = arr[loRow][loCol];
for(int row=loRow; row<=hiRow; row++){
max = Math.max(max, arr[row][midCol]);
}
boolean centralMax = true;
boolean rightMax = false;
boolean leftMax = false;
if(midCol-1 >= 0){
for(int row = loRow; row<=hiRow; row++){
if(arr[row][midCol-1] > max){
max = arr[row][midCol-1];
centralMax = false;
leftMax = true;
}
}
}
if(midCol+1 < M){
for(int row=loRow; row<=hiRow; row++){
if(arr[row][midCol+1] > max){
max = arr[row][midCol+1];
centralMax = false;
leftMax = false;
rightMax = true;
}
}
}
if(centralMax) return max;
if(rightMax) return kthLinearRow(arr, midCol+1, hiCol, loRow, hiRow);
if(leftMax) return kthLinearRow(arr, loCol, midCol-1, loRow, hiRow);
throw new RuntimeException("INCORRECT CODE");
}
// helper function that splits on the middle
int kthLinearRow(int[][] arr, int loCol, int hiCol, int loRow, int hiRow){
if(loRow==hiRow){
int ans = arr[loCol][loRow];
int foundCol = loCol;
for(int col=loCol; col<=hiCol; col++){
if(arr[loRow][col] > ans){
ans = arr[loRow][col];
foundCol = col;
}
}
if(!correctPeak(arr, loRow, foundCol)){
System.out.println("THIS PEAK IS WRONG");
}
return ans;
}
boolean centralMax = true;
boolean upperMax = false;
boolean lowerMax = false;
int midRow = (loRow+hiRow)/2;
int max = arr[midRow][loCol];
for(int col=loCol; col<=hiCol; col++){
max = Math.max(max, arr[midRow][col]);
}
if(midRow-1>=0){
for(int col=loCol; col<=hiCol; col++){
if(arr[midRow-1][col] > max){
max = arr[midRow-1][col];
upperMax = true;
centralMax = false;
}
}
}
if(midRow+1<N){
for(int col=loCol; col<=hiCol; col++){
if(arr[midRow+1][col] > max){
max = arr[midRow+1][col];
lowerMax = true;
centralMax = false;
upperMax = false;
}
}
}
if(centralMax) return max;
if(lowerMax) return kthLinearColumn(arr, loCol, hiCol, midRow+1, hiRow);
if(upperMax) return kthLinearColumn(arr, loCol, hiCol, loRow, midRow-1);
throw new RuntimeException("Incorrect code");
}
int[][] randomArray(){
int[][] arr = new int[N][M];
for(int i=0; i<N; i++)
for(int j=0; j<M; j++)
arr[i][j] = (int)(Math.random()*1000000000);
return arr;
}
boolean correctPeak(int[][] arr, int row, int col){//Function that checks if arr[row][col] is a peak or not
if(row-1>=0 && arr[row-1][col]>arr[row][col]) return false;
if(row+1<N && arr[row+1][col]>arr[row][col]) return false;
if(col-1>=0 && arr[row][col-1]>arr[row][col]) return false;
if(col+1<M && arr[row][col+1]>arr[row][col]) return false;
return true;
}
}
I've got an IndexOutOfBounds exception in the following program. It consists of three files:
Important are only two of them, the GUI is working fine. Here is the first one:
interface SudokuObserver {
public void modified(int i, int j);
}
public class SudokuData
{
public int[][] feld = new int[9][9];
public SudokuObserver obs = null;
public SudokuData()
{
int i,j;
for (i=0; i<9; i++) {
for (j=0; j<9; j++) {
feld[i][j] = 0;
}
}
}
public int getNumber(int x, int y)
{
return feld[x][y];
}
public void setNumber(int x, int y, int v)
{
feld[x][y] = v;
if (obs != null)
obs.modified(x, y);
}
public void setObserver(SudokuObserver o)
{
obs = o;
}
So the Sudoku field is allocated as a 9x9 integer array. The following file is called SudokuSolver and has an algorithm to write the possible numbers for each square into an ArrayList. Then the second algorithm works as following: He finds the square which has the minimum of possible numbers, sets the first of the numbers saved in the ArrayList on that square and does this recursive, so he starts again at defining the possible numbers for each square, taking the one with the smallest number of possibilities and picks the first one to put it into that field. A for-loop runs over the possible Numbers for each square while doing that.
import java.util.*;
public class SudokuSolver
{
SudokuData data;
public SudokuSolver(SudokuData d)
{
data = d;
}
{
/*Pseudoalgorithm:
- Inserts the numbers 1-9 into a Collection called res
- Looks at line x, which numbers are in there and erases them out of the
collection
- Looks at column y, which numbers are in there and erases them out of the
collection
- Looks in the 3x3 Square (x,y) which numbers are already in there and erases
them out of the collection
- Gives back the possible candidates for that field
*/
Here i initialize my ArrayList.
public ArrayList<Integer> offen(int x, int y)
{
ArrayList<Integer> res = new ArrayList<Integer>();
/* The collection is saved in an ArrayList */
int k = 0;
Here I just fill in the numbers 1-9 in my ArrayList.
for (int i=1;i<10;i++)
{
res.add(i);
}
Now comes the difficult part: I loop over j from zero to nine, then over k. The line is constant with the given x, the j runs over the columns, so i got every square in the given line, and in every square i check for every number from 1-9. Care: the index goes from 0-9 while the elements go from 1-9 so k has to be 0-9 cause the get()-method takes an index as input. If there is any compliance I remove the element from the ArrayList.
for (int j=0;j<9;j++)
{
for (k=0;k<9;k++)
{
if (this.data.feld[x][j] == (res.get(k)))
res.remove(k);
}
Same stuff as above for the columns, constant column and j loops.
for (k=0;k<9;k++)
{
if (this.data.feld[j][y] == res.get(k))
res.remove(k);
}
}
Now i get my inputs in two new variables, just because i had typed the code part below before with wrong variable names.
int m = x;
int n = y;
Here is the part for the 3x3 squares, i do this with if conditions, so this is just one of the 9 parts, I didn't want to post them all here, cause they just differ in a few constants. I check in which square my input x,y is, and then I loop over the square and check which numbers are there, which are also still in my ArrayList and remove them.
if (m<=2 && n<=2)
{
for (m=0;m<3;m++)
{
for (n=0;n<3;n++)
{
for (k=0;k<9;k++)
{
if (this.data.feld[m][n] == res.get(k))
res.remove(k);
}
}
}
}
Now I return the ArrayList
return res;
}
//findSolution() finds a Solution
public boolean findSolution()
{
/*Possible Strategy:
- Find the square, which has the fewest possible candidates
- If there are more than one candidates, who have the minimum of candidates,
take any of them
- If there are no more open candidates, there is a solution found. Return
true
- Loop over the candidates of this square and by setting the first possible
candidate into this square[x][y]
- Call the method findSolution() recursive to find in dependence of the set
value the values for the other fields
If there is a blind alley, take the next possible candidate (Backtracking!)
*/
int j = 0;
int k = 0;
int x = 0; // x coordinate of the field with the fewest open candidates
int y = 0; // y coordinate of the field with the fewest open candidates
int counter_offene_felder = 0; // counts the number of open fields
int min = 9;
I'm looping over j and k, looking if the number of possible candidates is more than 0, that means I'm running through the whole sudoku field and count the number of open fields.
for (j=0;j<9;j++)
{
for (k=0;k<9;k++)
{
if ( this.offen(j,k).size() >= 0)
{
counter_offene_felder += 1;
}
If the number is < than min = 9 possible candidates, i take it as the min and save the coordinates of that field
if ( (this.offen(j,k)).size() < min )
{
x = j;
y = k;
}
}
}
now i initialize and ArrayList for the field with the fewest possible candidates and put them into this ArrayList with my offen-method
ArrayList<Integer> candidate_list = this.offen(x,y);
for (k=0;k<this.offen(x,y).size();k++)
{ // runs over candidates
int v = this.offen(x,y).get(k); // takes the first candidate
this.data.setNumber(x,y,v); // writes the first candidate into square [x][y]
this.findSolution(); // calls findSolution() recursive
}
If there are no more open fields, I've found a solution
if (counter_offene_felder == 0)
{
return true;
}
else return false;
}
}
The problem is, that I get an IndexOutOfBounds Exception at line 39, at Index 8 Size 8. But I don't know why. :(
Not positive that this is where you are getting your error... but you could run into an issue when you do something like this.
for (k=0;k<9;k++)
{
if (this.data.feld[j][y] == res.get(k))
res.remove(k);
}
For instance, say that at k=1 the if statement evaluates to true. Then you will remove an element from the ArrayList. Then when k=8, and IndexOutOfBounds exception will be thrown because the ArrayList only contains 8 elements (0-7)
Assuming that no other threads will be modifying this.data.feld[][], you will only ever get one match when going through this loop.. so you could do something like this...
int match = -1;
for (k=0;k<res.size();k++) {
if (this.data.feld[j][y] == res.get(k)){
match = k;
break;
}
}
if(match != -1)
res.remove(match);
I think the contains() method will help eliminate your exceptions for this loop.
Try replacing your code with this:
for (m=0;m<3;m++)
{
for (n=0;n<3;n++)
{
if (res.contains(this.data.field[m][n]))
res.remove(res.indexOf(this.data.field[m][n]));
}
}
It will iterate over the data.field, and check the ArrayList to see if it contains the value at m,n. If it does, it will remove it.