I have a matrix of cells (buttons in my case), if I click on one button, I need to check if a nearby (plus shape) cell is empty, and if a cell is empty (only one can be), I need to swap the two cells (the empty one and the clicked one).
What I do now is:
if(j < 3)
if (!fbarr[i, j + 1].Visible)
swap(fbarr[i, j], fbarr[i, j + 1]);
if(j > 0)
if (!fbarr[i, j - 1].Visible)
swap(fbarr[i, j], fbarr[i, j - 1]);
if(i < 3)
if (!fbarr[i + 1, j].Visible)
swap(fbarr[i, j], fbarr[i + 1, j]);
if(i > 0)
if (!fbarr[i - 1, j].Visible)
swap(fbarr[i, j], fbarr[i - 1, j]);
Now personally I think this is ugly as hell.
Is there a nicer way to do this? (This is C# if it matters)
Thanks
Your current technique isn't necessarily bad, it just isn't DRY enough. You can also make the search space more explicit by getting the offsets into some kind of data structure. Here's an example using Tuples:
var offsets = new List<Tuple<int, int>>
{
Tuple.Create(0, 1),
Tuple.Create(0, -1),
Tuple.Create( 1, 0),
Tuple.Create(-1, 0)
};
foreach (var offset in offsets) {
int newI = i + offset.Item1;
int newJ = j + offset.Item2;
// New position must be within range
if (newI >= 0 && newI <= 3 && newJ >= 0 && newJ <= 3) {
if (!fbarr[newI, newJ].Visible) {
swap(fbarr[i, j], fbarr[newI, newJ]);
}
}
}
Related
I need a help in a enhancement to very popular dynamic programming question. Min/Max cost path
Question : There is a 2D matrix which has values (0,1,-1).
0 -> no cherry. can go here
1 -> cherry present. can go here
-1 -> thorn present. can't go here
we need to print maximum cherrys collected and entire path in which we can collect maximum cherrys.
input :
{{0, 1, -1}, {1, 0, -1},{1,1,1}};
output :
4
(0,0) -> (1,0) -> (2,0) -> (2,1) -> (2,2)
I can write the code to print the maximum cherrys collected but not able to get the logic to how to store the entire path. Since we decide which cell to be choosen while backtracking, it appears little tough. didnt find any web help in this regard. I'm stuck, Any help would be appreciated.
public int cherryPickup(int[][] grid) {
if (grid.length == 0) {
return -1;
}
int[][] dp = new int[grid.length][grid[0].length];
setDp(dp);
int forwardMax = getForwardMax(grid, dp, 0, 0);
return forwardMax;
}
private void setDp(int[][] dp) {
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
dp[i][j] = -1;
}
}
}
private int getForwardMax(int[][] grid, int[][] dp, int i, int j) {
if(dp[i][j] != -1) {
return dp[i][j];
}
if (grid[i][j] == -1) {
dp[i][j] = 0;
return dp[i][j];
}
if (i == grid.length - 1 && j == grid[0].length - 1) {
dp[i][j] = grid[i][j];
return dp[i][j];
}
if (i == grid.length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i, j + 1);
return dp[i][j];
}
if (j == grid[0].length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i + 1, j);
return dp[i][j];
}
dp[i][j] = grid[i][j] + Math.max(getForwardMax(grid, dp, i + 1, j), getForwardMax(grid, dp, i, j + 1));
return dp[i][j];
}
As per suggestion in the comment for having the path[][] and storing the index which is maximum.
Below code stores (1,1) also 1, which is incorrect.
private int getForwardMax(int[][] grid, int[][] dp, int i, int j, int[][] path) {
if(dp[i][j] != -1) {
return dp[i][j];
}
if (grid[i][j] == -1) {
dp[i][j] = 0;
return dp[i][j];
}
if (i == grid.length - 1 && j == grid[0].length - 1) {
dp[i][j] = grid[i][j];
return dp[i][j];
}
if (i == grid.length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i, j + 1, path);
path[i][j] =1;
return dp[i][j];
}
if (j == grid[0].length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i + 1, j, path);
path[i][j] =1;
return dp[i][j];
}
int left = getForwardMax(grid, dp, i + 1, j, path);
int right = getForwardMax(grid, dp, i, j + 1, path);
int max = Math.max(left, right);
if(max == left) {
path[i+1][j] = 1;
} else {
path[i][j+1] = 1;
}
dp[i][j] = grid[i][j] + max;
return dp[i][j];
}
Well if you write your dynamic programming top down (as you did), restoring actual answer is actually very easy.
So you have a function getForwardMax which for given cell, return maximum amount we can collect moving right or down
You also know starting position, so all you need to do is build the answer step by step:
Let's say you're in some cell (r,c)
if there is only one possible move (you're at border) just do it
otherwise we can either move to (r+1,c) or (r,c+1)
we also know how much we will earn by moving to those cells and completing our path to the goal from getForwardMax function
So we just pick move that gives better result
Ok, bottom up DP is a correct solution as yours. I just realized you won't need separate path[][] to store the path and iterate over them.
You can use a simple while loop and choose the best among the 2 options of right and down.
If both happen to have same values, you need not worry as one grid could have multiple correct solutions. So, choosing either one in case of clash will still give you a correct solution.
We start from (0,0).
If value contained in dp[x][y+1] cell at the right + current grid[x][y] gives us the value same as dp[x][y], we move right, else we move down.
Snippet:
int x = 0,y = 0;
while(x != rows-1 || y != cols-1){
System.out.println("( " + x + " , " + y + " )");
if(x+1 < rows && grid[x][y] + dp[x+1][y] == dp[x][y]){
x++;
}else if(y + 1 < cols && grid[x][y] + dp[x][y+1] == dp[x][y]){
y++;
}
}
System.out.println("( " + x + " , " + y + " )");
Full Code: https://ideone.com/lRZ6E5
I have a 3 * 3 grid. I have a 9 letter word that I have to arrange randomly in the grid. The arrangement should be such that there is a valid path in the grid that covers the word sequentially. Valid moves in the grid are: up, down, left, right, diagonal. Cant visit the same element again.
Could you please point me in the right direction? I just want to know what algorithm I should use in this case?
Sorry if I wasn't clear earlier. By random arrangement I meant that the path should not be fixed.
if I have the word BUZZINGLY, a sample path can be:
| B U Z |
| N I Z |
| G L Y |
, so whatever arrangement I choose should be different each time.
There aren't very many alternatives and very few if you eliminate symmetric variants. You can just compute them all, store them, and choose one randomly. Then choose a random rotation and mirror operation.
To get you started, this considers the 3 possible starts: corner, center, and mid-edge, and finds all the valid paths.
#include <stdio.h>
int b[3][3];
void print(void) {
for (int i = 0; i < 3; ++i) printf("%d %d %d\n", b[i][0], b[i][1], b[i][2]);
printf("\n");
}
void search(int n, int i, int j) {
if (i < 0 || j < 0 || i > 2 || j > 2 || b[i][j]) return;
b[i][j] = n;
if (n == 9) print();
else {
search(n + 1, i + 1, j);
search(n + 1, i - 1, j);
search(n + 1, i, j + 1);
search(n + 1, i, j - 1);
search(n + 1, i + 1, j + 1);
search(n + 1, i - 1, j + 1);
search(n + 1, i + 1, j - 1);
search(n + 1, i - 1, j - 1);
}
b[i][j] = 0;
}
int main(void) {
search(1, 0, 0); search(1, 0, 1); search(1, 1, 1);
return 0;
}
Levenshtein distance can be computed iteratively using two rows this way:
https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows
I came across the Optimal String alignment distance that does take into account the transposition. Wikipedia says that it can be computed using a straightforward extension of the regular Levenshtein algorithm:
if i > 1 and j > 1 and a[i-1] = b[j-2] and a[i-2] = b[j-1] then
d[i, j] := minimum(d[i, j],
d[i-2, j-2] + cost) // transposition
However, I'm not able to port the pseudo-code algorithm's extension on that page to the iterative version's code. Any help is greatly appreciated.
You need three rows to compute this new version, I can't check the code but I am quite confident about it:
int DamerauLevenshteinDistance(string s, string t)
{
// degenerate cases
if (s == t) return 0;
if (s.Length == 0) return t.Length;
if (t.Length == 0) return s.Length;
// create two work vectors of integer distances
int[] v0 = new int[t.Length + 1];
int[] v1 = new int[t.Length + 1];
int[] v2 = new int[t.Length + 1];
// initialize v0 (the previous row of distances)
// this row is A[0][i]: edit distance for an empty s
// the distance is just the number of characters to delete from t
for (int i = 0; i < v0.Length; i++)
v0[i] = i;
// compute v1
v1[0] = 0;
// use formula to fill in the rest of the row
for (int j = 0; j < t.Length; j++)
{
var cost = (s[0] == t[j]) ? 0 : 1;
v1[j + 1] = Minimum(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost);
}
if (s.Length == 1) {
return v1[t.Length];
}
for (int i = 1; i < s.Length; i++)
{
// calculate v2 (current row distances) from the previous rows v0 and v1
// first element of v2 is A[i+1][0]
// edit distance is delete (i+1) chars from s to match empty t
v2[0] = i + 1;
// use formula to fill in the rest of the row
for (int j = 0; j < t.Length; j++)
{
var cost = (s[i] == t[j]) ? 0 : 1;
v2[j + 1] = Minimum(v2[j] + 1, v1[j + 1] + 1, v1[j] + cost);
if (j > 0 && s[i] = t[j-1] && s[i-1] = t[j])
v2[j + 1] = Minimum(v2[j+1],
v0[j-1] + cost);
}
// copy v2 (current row) to v1 (previous row) and v1 to v0 for next iteration
for (int j = 0; j < v0.Length; j++)
v0[j] = v1[j];
v1[j] = v2[j];
}
return v2[t.Length];
}
The original code is coming from the wikipedia implementation mentioned above.
Question
Jeff loves playing games, Gluttonous snake( an old game in NOKIA era ) is one of his favourites.
However, after playing gluttonous snake so many times, he finally got bored with the original rules.
In order to bring new challenge to this old game, Jeff introduced new rules :
The ground is a grid, with n rows and m columns(1 <= n, m <= 500).
Each cell contains a value v (-1 vi 99999), if v is -1, then this cell is blocked, ≤ ≤ and the snake
can not go through, otherwise, after the snake visited this cell, you can get v point.
The snake can start from any cell along the left border of this ground and travel until it finally
stops at one cell in the right border.
During this trip, the snake can only go up/down/right, and can visit each cell only once.
Special cases :
a. Even in the left border and right border, the snake can go up and down.
b. When the snake is at the top cell of one column, it can still go up, which demands the player to pay all current points , then the snake will be teleported to the bottom cell of this column and vice versa.
After creating such a new game, Jeff is confused how to get the highest score. Please help him to write a program to solve this problem.
Input
The first line contains two integers n (rows) and m (columns), (1 <= n, m <= 500), separated by a single space.
Next n lines describe the grid. Each line contains m integers vi (-1 ≤ vi ≤ 99999)
vi = -1 means the cell is blocked.
Output
Output the highest score you can get. If the snake can not reach the right side, output -1.
Limits
• Memory limit per test : 256 megabytes
• Time limit per test : The faster the better Compile
4 4
-1 4 5 1
2 -1 2 4
3 3 -1 3
4 2 1 2
I have solved the question with code given below then the interviewer changes the question and asked that now the snake always has to take a particular point in its route that is path including that particular point are only valid like if point is (2,1) then it has to take 3 in its path always. and than we have to find the max sum ? i was not able to do it in the interview please please any one help it , just provide link only where this type of problem is done. I applied dfs interviewer told dfs is wrong in this question , i am not able to figure it out why it is wrong and what can be better algorithm to find the answer
Code
import java.util.Scanner;
public class worksApplication {
private static int rows;
private static int col;
private static int[][] a;
private static boolean[][] check;
private static int max1;
private static int max;
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
rows = sc.nextInt();
col = sc.nextInt();
a = new int[rows][col + 1];
check = new boolean[rows][col];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < col + 1; j++) {
if (j == col) {
a[i][j] = -1;
} else
a[i][j] = sc.nextInt();
}
}
for (int i = 0; i < rows; i++) {
if (a[i][0] != -1) {
check[i][0] = true;
solve(i, 0, a[i][0]);
check[i][0] = false;
max1 = Math.max(max, max1);
}
}
System.out.println(max1);
}
private static void solve(int i, int j, int sum) {
// TODO Auto-generated method stub
if (i - 1 == -1 && check[rows - 1][j] == false && a[rows - 1][j] != -1) {
check[rows - 1][j] = true;
solve(rows - 1, j, a[rows - 1][j]);
check[rows - 1][j] = false;
}
if (i - 1 >= 0 && check[i - 1][j] == false && a[i - 1][j] != -1) {
check[i - 1][j] = true;
solve(i - 1, j, sum + a[i - 1][j]);
check[i - 1][j] = false;
}
if (a[i][j + 1] != -1 && check[i][j + 1] == false) {
check[i][j + 1] = true;
solve(i, j + 1, sum + a[i][j + 1]);
check[i][j + 1] = false;
}
if (i + 1 == rows && a[0][j] != -1 && check[0][j] == false) {
check[0][j] = true;
solve(0, j, a[0][j]);
check[0][j] = false;
}
if (i + 1 < rows && a[i + 1][j] != -1 && check[i + 1][j] == false) {
check[i + 1][j] = true;
solve(i + 1, j, sum + a[i + 1][j]);
check[i + 1][j] = false;
}
if (max < sum) {
max = sum;
}
}
}
I am working my way through the book Introduction to Algorithms, 3rd edition. One of the first things explained is the insertion sort. On page 18 there is some pseudo code:
A = { 5, 2, 4, 6, 1, 3 };
INSERTION-SORT(A)
1 for j = 2 to A.length
2 key = A[j]
4 i = j - 1
5 while (i > 0 and A[i] > key)
6 A[i + 1] = A[i]
7 i = i - 1
8 A[i + 1] = key
It says that pseudo code is used so that it is easily translated to any kind of language (C, C++, Java, they don't mention, but I guess C# too). Since I program in C#, I translated it in LinqPad.
int[] a = { 5, 2, 4, 6, 1, 3 };
for (var j = 1; j < a.Length; j++)
{
var key = a[j];
var i = j - 1;
while(i > 0 && a[i] > key)
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
a.Dump();
You're probably going to ask, why does j start at 1, when it clearly says 2? In the book, the array has an index starting at 1. And yes, I now I probably should have updated all the [i - 1] and [i + i] as well.
Anyways, after I was done, I run the code and notice that it doesn't actually sort correctly. The output is { 5, 1, 2, 3, 4, 6 }. It was late and should have stopped, but I struggled on to make the code correct. I did everything, even taking the pseudo code as is from the book (starting at 2). Still not the correct output.
I contacted one of the professors of the book, and he send me the code for the insertion sort, in C:
void insertion_sort(int *A, int n) {
for (int j = 2; j <= n; j++) {
int key = A[j];
int i = j-1;
while (i > 0 && A[i] > key) {
A[i+1] = A[i];
i--;
}
A[i+1] = key;
}
}
Translated in C#:
int[] a = { 5, 2, 4, 6, 1, 3 };
for (var j = 2; j <= a.Length; j++)
{
var key = a[j];
var i = j - 1;
while(i > 0 && a[i] > key)
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
I get an array out of bounds. Okay then maybe:
int[] a = { 5, 2, 4, 6, 1, 3 };
for (var j = 2; j <= a.Length - 1; j++)
{
var key = a[j];
var i = j - 1;
while(i > 0 && a[i] > key)
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
Output: { 5, 1, 2, 3, 4, 6 }
I'm thinking, this can't be correct. The pseudo code says 2 to array.Length. Is that 2 < array.Length, or 2 <= array.Length? What is going on here?
I personally think it is because of the 0 > 0 predicate in the while loop. It actually falls short one time each time.
My explanation (from my email sent to the professor, to lazy to type it all over):
The reason why the loop still ends up with { 5, 1, 2, 3, 4, 6 } is because of the i > 0 predicate. Every time in the while loop you subtract 1 of i (i--). This will eventually lead to 0 > 0 which ends up false (only 0 == 0 will return true), but this is when the loop still needs to run one more time. It continuously falls one short. It should go do the while loop 1 more time to properly sort.
Another explanation:
When j starts with 2, key == 4, i == 1 and a[i] == 2. The while loop won't run in this case because 2 > 0 but 2 isn't greater than 4.
j == 3,
key == 6,
i == 2,
a[i] == 4
While loop won't run because 4 is not greater than 6
j == 4,
key == 1,
i == 3,
a[i] == 6
While loop runs this time:
a[i + 1] = a[i] -> a[4] = a[3] -> { 5, 2, 4, 6, 6, 3 }
i-- -> i == 2
Again while loop because 2 > 0 and 4 > 1
a[i + 1] = a[i] -> a[3] = a[2] -> { 5, 2, 4, 4, 6, 3 }
i-- -> i == 1
Again while loop because 1 > 0 and 2 > 1
a[i + 1] = a[i] -> a[2] = a[1] -> { 5, 2, 2, 4, 6, 3 }
i-- -> i == 0
And here is where it goes (in my opinion) wrong. i is now equal to zero, but the while loop should run one more time to get the 5 out of the zero-th position.
The professor assures me that he is correct, but I can't get the right output. Where is my thinking going wrong?
The array in the C code that got sent to me by the professor was actually starting with an index of 1. I did not know this and checking upon C arrays I saw that they all start with 0. Yes, then the C code doesn't produce the correct output. The professor explained this to me and the pieces now fall into its place.
I think the prof is using 1-based array notation, so with while (i > 0 && a[i] > key), you are missing the a[0] element in the loop. Change your initial code to this then it works:
for (var j = 1; j < a.Length; j++)
{
var key = a[j];
var i = j - 1;
while(i >= 0 && a[i] > key) <----------- Try this, or you'd miss the first number
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
Also, if you want to use the professor's code, just ignore the 0-th element there.
On a side note, who did you contact? Rivest? Corman? Next time I get confused I think I'll try to contact him too, since it seems this professor reply mails:)
You should not think about translating the pseudocode, but about
translating your understanding of the algorithm.
The array is completely unsorted at first. The algorithm works by
taking successive unsorted elements and inserting them into the
already sorted part. The starting "sorted part" is the first element,
which is trivially "sorted". So, the first element to insert is the
second. Which is the index of the second element? Your j has to
start from there.
Then, i has to go through each of the sorted elements' indices,
backwards, until it either finds the place to insert the current value
or runs out of elements. So, where does it have to start, and where
does it have to end? Take care that it actually looks at each element
is has to.
Off-by-one errors are notoriously difficult to spot (and mixing
notions of 1-based and 0-based arrays surely does not help), but don't
just fiddle around until it seems to work. Try to understand what the
code is actually doing.
I believe your argument about i>0 is correct, regardless of what the prof. says. In the pseudo-code, the loop is while i > 0 and the array indexing starts with 1. In C#, array indexing starts with 0, therefore you should have while i >= 0.
I experienced the same problem. Below is the code in C which implements the above pseudo-code correctly. I am not using pointers, like other solutions.
Indeed, the tricky part about this was that the pseudo code is using 1-based array notations unlike most programming languages!
#include <stdio.h>
int main(void)
{
int A[] = { 50, 20, 10, 40, 60, 30 };
int j, key, len, i;
len = (sizeof(A)) / (sizeof(A[0]));
for (j = 1; j < 6; j++) { <-- Change here
key = A[j];
// Insert key into the sorted sequence A[1 .. j - 1].
i = j - 1;
while (i >= 0 && A[i] > key) { <-- Change here
A[i + 1] = A[i];
i--;
}
A[i + 1] = key;
}
for (int z = 0; z < len; z++) {
printf("%d ", A[z]);
}
printf("\n");
}
I also came across your problem, and I found the solution to this. I coded the algorithm in java as below.
int a[] = {5,2,4,3,1};
int key;
int i;
for(int j = 0; j < 5; j++)
{
key = a[j];
i = j - 1;
while(i>=0 && a[i]>key)
{
a[i+1]= a[i];
i--;
}
a[i+1] = key;
for(int k=0; k<a.length;k++)
{
System.out.print(a[k]+" ");
}
}
Remember: A.length goes from 0 to n, so Length should be A.Length -1. I made this algorithm for my students in C++ in spanish, using that book. Is simple to translate in C#.
some translation so you can understand better
largo = length
actual = current
cadena = chain
void InsertionSort::Sort(char cadena[])
{
int largo = strlen(cadena) - 1;
char actual = '0';
int i = 0;
for (int j = 1; j <= largo; j++)
{
actual = cadena[j];
i = j - 1;
while(i >= 0 && cadena[i] > actual)
{
cadena[i + 1] = cadena[i];
i--;
}
cadena[i + 1] = actual;
}
}