Something is wrong with my do-while loop involving character position - java

when i run the program the output is just continuous and doesnt end. The goal here is to try and get the + all the way to the left or the right, then print which side won and how many turns it took.
the code is executing now, but it only moves left and right one space from the middle, which makes me think its now with the for loops
package test;
import java.util.Scanner;
import java.lang.Math;
public class Test {
public static int MAX_LENGTH = 21;
public static int MIN_LENGTH = 5;
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter the length of the rope: ");
int ropeLength = keyboard.nextInt();
while (ropeLength < MIN_LENGTH || ropeLength > MAX_LENGTH || ropeLength % 2 != 1) {
System.out.println("Thats not a valid length (odd number between 5 and 21)");
System.out.print("Enter the length of the rope: ");
ropeLength = keyboard.nextInt();
}
char a;
String flag = " ";
for (int i = 0; i < ropeLength / 2; i += 1) {
flag += "-";
}
flag += "+";
for (int i = 0; i < ropeLength / 2; i += 1) {
flag += "-";
}
System.out.println("");
do {
flag = "";
double rand = Math.random();
int i;
if (rand > 0.5) {
for (i = 0; i < (ropeLength / 2) - 1; i++) {
flag += "-";
}
flag += "+";
for (i = 0; i < (ropeLength / 2) + 1; i++) {
flag += "-";
}
System.out.println( flag );
}
if (rand < 0.5) {
for (i = 0; i < (ropeLength / 2) + 1; i++) {
flag += "-";
}
flag += "+";
for (i = 0; i < (ropeLength / 2) - 1; i++) {
flag += "-";
}
System.out.println( flag );
}
} while (flag.charAt(1) != '+' || flag.charAt(ropeLength) != '+');
if (flag.charAt(0) == '+') {
System.out.println("\nLeft side wins!");
}
else {
System.out.println("\nRight side wins!");
}
System.out.println("It took steps");
}
}

You need to pay attention to the position of the flag. Currently you only put the flag one position to the left or right of the center. You might want to pull your flag printing method into a helper method to ease readability and make it clearer what you need to keep track of.
Once you replace your three printing methods with calls to this method, it should become clearer what you need to keep track of and pass as parameters in order to get everything working.
Something like this should get you started:
public static void printFlag(int ropeLength, int flagPosition) {
for (int i = 0; i < flagPosition; i += 1) {
System.out.print("-");
}
System.out.print("+");
for (int i = flagPosition + 1; i < ropeLength; i += 1) {
System.out.print("-");
}
System.out.println();
}
Note: Using a StringBuilder instead of a bunch of print() calls is probably a good idea, but I'll leave that as an exercise to the reader.

There are multiple problems with the logic in your code.
1) In your do-while loop you always just keep appending to flag. This means that for every iteration your flag just gets bigger, it doesn't actually move the + that you have in there. You can have a temporary variable called 'nextState' to generate the next state and then set flag equal to it at the end.
Code:
String nextState = "";
if (rand > 0.5) {
for (i = 0; i < (ropeLength / 2) - 1; i++) {
nextState += "-";
}
nextState += "+";
for (i = 0; i < (ropeLength / 2) + 1; i++) {
nextState += "-";
}
flag = nextState;
System.out.println(flag);
}
2) You are checking if flag.charAt(1)=='+' and flag.charAt(ropeLength)=='+'. Since arrays have a 0 based index this is incorrect, you actually need 0 and ropeLength-1 respectively. (I do note that you did it correctly below the do-while loop).
3) The problem with your do-while loop is that if you correct errors 1 and 2, you will definitely move the + to the left and to the right, however you will NEVER be able to move it to position 0 (all the way left) or position ropeLength-1 (all the way right) with your current logic. Something like this can be done and you can similarly do it for the other if.
if (rand > 0.5) {
i = 0;
while (i + 1 < flag.length() && flag.charAt(i + 1) != '+') {
nextState += "-";
i++;
}
nextState += "+";
i++;
while (i < flag.length()) {
nextState += "-";
i++;
}
flag = nextState;
}
4) You initialize flag = " "; but you just want flag = ""; (an empty string) as flag only contains -'s and a +.
5) while (flag.charAt(0) != '+' || flag.charAt(ropeLength - 1) != '+'); is incorrect. It shold be && because your original statement will ALWAYS be true and the loop will never end. Your original statement will only be false if there is a + in the begining and in the end which is impossible.
6) Not really an issue but with your if (rand > 0.5) you could have used an if-else instead of two if's. If rand is exactly equal to 0.5 your code does nothing. Since you have to count steps you need to change one of them to rand <= 0.5 or rand >= 0.5 or just use an if-else.
Once you fix these problems. You are good to go. Great effort!

You never reset your flag at the start of each iteration
and you need the && operator as knoight says
you need something like:
do {
flag = "";
... your existing code
} while ( (flag.charAt(1) != '+') && (flag.charAt(ropeLength) != '+') );
it seems like your flag is going to randomly jump around with the fixes i've proposed above. perhaps you want to simply move the flag left or right one spot on each iteration?
you can do that like this:
int flagpos = (ropeLength / 2)+1;
do {
flag = "";
double rand = Math.random();
int i;
if (rand > 0.5) {
flagpos++;
else
flagpos--;
for (i = 0; i < flagpos - 1; i++)
flag += "-";
flag += "+";
for (i = flagpos + 1; i < ropeLength ; i++)
flag += "-";
System.out.println( flag );
} while (flag.charAt(1) != '+' || flag.charAt(ropeLength) != '+');

You need to change the last line, from:
while (flag.charAt(1) != '+' || flag.charAt(ropeLength) != '+');
to
while (flag.charAt(0) != '+' && flag.charAt(ropeLength) != '+');
Using || means that only ONE of those conditions has to be true, and since you are using a while loop, you're saying that if the first position is not equal to + OR the last position is not equal to + then you want the loop to continue.

As stated earlier the follow will work.
do {
flag = "";
//do stuff
} while (flag.charAt(1) != '+' && flag.charAt(ropeLength-1) != '+');
Problem is your flipping a coin to move the rope and the larger the rope length the smaller the chance you will ever reach the end.

Related

Printing only NON-BOUNDARY and CORNER elements of an (n*n) array

I am to write a program that prints ONLY the NON-BOUNDARY AND CORNER elements of an (n*n) array, for my assignment, and this is the main part of the code:
The output I am getting is this:
As you can see, the non-boundary elements (6,7,10,11) are not in their correct positions, which I believe, is because of incorrect printing of tab spaces within the loop. (My code is totally a mess) I would like some help or suggestions to fix this. Thanks!
I generally find that flattening things (the if-conditions in particular), and putting conditions into boolean-returning methods helps. Try something like
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++ {
if (isCorner(i,j,n) || !isEdge(i,j,n)) {
//...
} else {
//...
}
}
System.out.println();
}
where isCorner(i,j,n) and isEdge(i,j,n) are defined something like
public boolean isCorner(int row, int column, int gridSize) {
//...
}
A you got a solution, just missing spaces, I'll add some smart things:
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
boolean visible = (i % (n - 1) == 0) == (j % (n - 1) == 0);
if (visible) {
System.out.printf(" %4d", a[i][j]);
} else {
System.out.print(" ");
}
}
System.out.println();
}
No longer any problems with tabs "\t", though I used spaces here.
Keep it simple, too many cases just cause problems - as you experienced.
The trick here is to consider whether to print or not. Hence I started with
a variable visible.
The border condition
i == 0 || i == n - 1
could also be written with modulo as
i % (n - 1) == 0
If this is "too smart", hard to grasp reading:
boolean iOnBorder = i % (n - 1) == 0;
boolean jOnBorder = j % (n - 1) == 0;
boolean visible = iOnBorder == jOnBorder;
The "X" pattern checks the _equivalence of i-on-border and j-on-border.
For the rest: formatted printf allows padding of a number.
Try this i have optimized your if condition
No need to again check for i == 0 or i == n-1
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==0 || i==n-1){
if(j==0 || j==n-1){
System.out.print(a[i][j]);
}
}else{
if(j != 0 && j!= n-1){
System.out.print(a[i][j]);
}
}
System.out.print("\t");
}
System.out.println();
}
Just gave a try in case you might find it helpful.
public static void main(String[] args) throws ParseException {
int[][] ar = new int[4][4];
int[] input = new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
int pointer=0;
int imin=0,jmin=0,imax=3,jmax=3;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
ar[i][j]=input[pointer];
pointer++;
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(!((i==imax && j==jmin)||(i==imin && j==jmax)||i==j) && //For skipping the corners
(i == imin || j == jmin || i == imax || j == jmax)){// Not to print the borders
continue;
}
else {
System.out.println(ar[i][j]);
}
}
}
}

what can cause this particular palindrome a logic error

The following method was written to determine whether its String parameter reads identically left-to-right and right-to-left (the so called palindrome). I am having trouble finding the logic error of this palindrome. I believe the error is that the two conditions in the whole loop can affect checking the characters in the string. Please correct me if I am wrong so I can propose a proper solution.
This may be a stupid question to many of you, but I am new to java programming and this is written question on paper not actual code if that makes sense.
Your logic will only work if the length of input string is an odd number, i.e. 1,3,5 etc.
Because in case the length is even, i will never be equal to j. Example for a string "abba":
while (i == j && S.charAt(i) == S.charAt(j)) { // i = 0, j = 3
i++;
j--;
}
iteration-2:
while (i <= j && S.charAt(i) == S.charAt(j)) { // i = 1 , j = 2
i++;
j--;
}
iteration-3:
while (i <= j && S.charAt(i) == S.charAt(j)) { // i = 2 , j = 1
i++;
j--;
}
This will finally result in StringIndexOutOfBoundsException when i reaches negative value and j reaches a value greater than length of string.
Try below code:
static boolean isPalidrome(String s) {
int i = 0;
int j = s.length() - 1;
while( i <= j && s.charAt(i) == s.charAt(j)) {
i ++;
j--;
}
return i >= j;
}
your code will fail if input string is something like "zz" or "xxxx" meaning even length with same characters so ideally you can try with something like this :
public static boolean isPal(String str) {
int start = 0;
int end = str.length() - 1;
while (start < end) {
final char f = str.charAt(start++);
final char b = str.charAt(end--);
if (f != b) {
return false;
}
}
return true;
}
You may apply following changes in your own code. There are basically two changes which are in your termination condition of while loop i.e. i <= j and return condition of (i >= j)
public static boolean isPalindrome(String S) {
int i = 0, j = S.length() - 1;
while (i <= j && S.charAt(i) == S.charAt(j)) {
i++;
j--;
}
return (i >= j);
}

How would one go about printing out a certain pattern to the console, given a random size?

I have a homework assignment for my computer science class in school, in which we have to print out the following pattern, of random size (width, height).
..............................X..............................
..................................X..........................
.......................................X.....................
...........................................X.................
...............................................X.............
...................................................X.........
......................................................X......
........................................................X....
..........................................................X..
...........................................................X.
............................................................X
...........................................................X.
..........................................................X..
........................................................X....
......................................................X......
...................................................X.........
...............................................X.............
...........................................X.................
.......................................X.....................
..................................X..........................
..............................X..............................
..........................X..................................
.....................X.......................................
.................X...........................................
.............X...............................................
.........X...................................................
......X......................................................
....X........................................................
..X..........................................................
.X...........................................................
X............................................................
.X...........................................................
..X..........................................................
....X........................................................
......X......................................................
.........X...................................................
.............X...............................................
.................X...........................................
.....................X.......................................
..........................X..................................
..............................X..............................
I'm almost 100% certain that my way of going about it is wrong, considering most of it is hard coded. I've spent hours thinking of different ways to go about the problem. I tried finding a formula for the curve, but I cannot, for the life of me, find one that fits perfectly. Also, even if I did have a formula, I don't know how to go about implementing it while printing to the console. My code currently only prints a fixed size of the pattern.
My code:
String pattern = "X";
String background = ".";
for(int i = 31; i < 61; i += 0) {
String output = "";
for(int j = 0; j < 61; j++) {
if(j == i) {
output += pattern;
} else {
output += background;
}
}
output = output.substring(2);
System.out.println(output);
if(i == 35) i += 5;
else if(i > 30 && i < 52) i += 4;
else if(i == 52) i += 3;
else if(i >= 55 && i < 59) i += 2;
else i++;
}
for(int i = 59; i >= 31; i += 0) {
String output = "";
for(int j = 0; j < 61; j++) {
if(j == i) {
output += pattern;
} else {
output += background;
}
}
output = output.substring(2);
System.out.println(output);
if(i <= 59 && i >= 57) i -= 2;
else if(i == 55) i -= 3;
else if(i <= 52 && i > 40) i -= 4;
else if(i == 40) i -= 5;
else i -= 4;
}
for(int i = 27; i >= 0; i += 0) {
if(i <= 1) break;
String output = "";
for(int j = 0; j < 61; j++) {
if(j == i) {
output += pattern;
} else {
output += background;
}
}
output = output.substring(2);
System.out.println(output);
if(i == 31) i -= 4;
else if(i == 27) i -= 5;
else if(i == 10) i -= 3;
else if(i <= 7 && i >= 5) i -= 2;
else if(i <= 5) i--;
else i -= 4;
}
for(int i = 3; i <= 31; i += 0) {
String output = "";
for(int j = 0; j < 61; j++) {
if(j == i) {
output += pattern;
} else {
output += background;
}
}
output = output.substring(2);
System.out.println(output);
if(i >= 3 && i <= 5) i += 2;
else if(i == 7) i += 3;
else if(i >= 10 && i <= 18) i += 4;
else if(i == 22) i += 5;
else i += 4;
}
Obviously, my way is inefficient and incorrect. I don't want the code typed out for me, but some pseudocode that points me in the right direction would be very much appreciated.
Pattern you show reminds me of sinusoid.
Though my Sine Wave Printer doesn't 100% match with the original output, it can give you an idea where to start. You can try rotating and joining several parabolas or graphs of other math functions that come to your mind, or play with the example below to get what you need.
Example
The following code snippet prints 'X' relying on Math.sin function (note that it uses angle in radians as argument):
// Configurations
Integer DEFAULT_ROW_LEN = 61;
Integer NUMBER_OF_ROWS = 1000;
char DEFAULT_ROW_CONTENT = '.';
Double SPEED = 2.8;
// Preparing row of dots
StringBuilder row = new StringBuilder();
for (int i = 0; i < DEFAULT_ROW_LEN; i++) {
row.append(DEFAULT_ROW_CONTENT);
}
for (int i = 0; i < NUMBER_OF_ROWS; i += SPEED) {
// Loop progress
double relativeProgress = i / DEFAULT_ROW_LEN.doubleValue();
// In projection on a circle
double circleProgress = relativeProgress * Math.PI * 2;
// Remember that sin goes from -1 to +1, but we need to fit the curve within 0 to +1
double consoleProgress = (Math.sin(circleProgress) + 1) / 2;
// Exact index in the row to highlight
int exactPosition = (int) (consoleProgress * DEFAULT_ROW_LEN);
row.setCharAt(exactPosition, 'X');
// Print current progress and restore defaults
System.out.println(row);
row.setCharAt(exactPosition, DEFAULT_ROW_CONTENT);
}
Output
..............................X..............................
....................................X........................
..........................................X..................
................................................X............
....................................................X........
........................................................X....
...........................................................X.
............................................................X
............................................................X
...........................................................X.
.........................................................X...
.....................................................X.......
.................................................X...........
............................................X................
......................................X......................
................................X............................
.........................X...................................
...................X.........................................
..............X..............................................
.........X...................................................
.....X.......................................................
..X..........................................................
X............................................................
X............................................................
X............................................................
..X..........................................................
......X......................................................
..........X..................................................
...............X.............................................
.....................X.......................................
...........................X.................................
.................................X...........................
Ok as requested, not gonna mouth feed you with code but rather a direction towards your coding pattern
The bottom line is to use methods, they are amazing features and helps you simplify your problem (and your thinking pattern).
One method, I particularly find useful is to print a line printLine(int length,int location,char c){...}
where length is the length of the line, location is where the char c should be printed.
another method you should consider is to calculate X location: getLocation(int length,int prev) : which uses the previous location and calculate the next one .
now all you need to do is loop through the number of lines, calculate next location and print the line.
I hope this helps you understand the problem better.

Review an answer - Decode Ways

I'm trying to solve a question and my question here is why doesn't my solution work?. Here's the question and below's the answer.
Question taken from leetcode: http://oj.leetcode.com/problems/decode-ways/
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). The number of ways decoding "12" is 2.
My solution:
The point with my solution is going backwards and multiplying the number of options if a split is found. By split I mean that digits can be interpreted in two ways. For example: 11 can interpreted in two ways 'aa' or 'k'.
public class Solution {
public int numDecodings(String s) {
if (s.isEmpty() || s.charAt(0) == '0') return 0;
int decodings = 1;
boolean used = false; // Signifies that the prev was already use as a decimal
for (int index = s.length()-1 ; index > 0 ; index--) {
char curr = s.charAt(index);
char prev = s.charAt(index-1);
if (curr == '0') {
if (prev != '1' && prev != '2') {
return 0;
}
index--; // Skip prev because it is part of curr
used = false;
} else {
if (prev == '1' || (prev == '2' && curr <= '6')) {
decodings = decodings * 2;
if (used) {
decodings = decodings - 1;
}
used = true;
} else {
used = false;
}
}
}
return decodings;
}
}
The failure is on the following input:
Input:"4757562545844617494555774581341211511296816786586787755257741178599337186486723247528324612117156948"
Output: 3274568
Expected: 589824
This is a really interesting problem. First, I will show how I would solve this problem. We will see that it is not that complicated when using recursion, and that the problem can be solved using dynamic programming. We will produce a general solution that does not hardcode an upper limit of 26 for each code point.
A note on terminology: I will use the term code point (CP) not in the Unicode sense, but to refer to one of the code numbers 1 though 26. Each code point is represented as a variable number of characters. I will also use the terms encoded text (ET) and clear text (CT) in their obvious meanings. When talking about a sequence or array, the first element is called the head. The remaining elements are the tail.
Theoretical Prelude
The EC "" has one decoding: the CT "".
The EC "3" can be destructured into '3' + "", and has one decoding.
The EC "23" can be destructured as '2' + "3" or '23' + "". Each of the tails has one decoding, so the whole EC has two decodings.
The EC "123" can be destructured as '1' + "23" or '12' + "3". The tails have two and one decodings respectively. The whole EC has three decodings. The destructuring '123' + "" is not valid, because 123 > 26, our upper limit.
… and so on for ECs of any length.
So given a string like "123", we can obtain the number of decodings by finding all valid CPs at the beginning, and summing up the number of decodings of each tail.
The most difficult part of this is to find valid heads. We can get the maximal length of the head by looking at a string representation of the upper limit. In our case, the head can be up to two characters long. But not all heads of appropriate lengths are valid, because they have to be ≤ 26 as well.
Naive Recursive Implementation
Now we have done all the necessary work for a simple (but working) recursive implementation:
static final int upperLimit = 26;
static final int maxHeadSize = ("" + upperLimit).length();
static int numDecodings(String encodedText) {
// check base case for the recursion
if (encodedText.length() == 0) {
return 1;
}
// sum all tails
int sum = 0;
for (int headSize = 1; headSize <= maxHeadSize && headSize <= encodedText.length(); headSize++) {
String head = encodedText.substring(0, headSize);
String tail = encodedText.substring(headSize);
if (Integer.parseInt(head) > upperLimit) {
break;
}
sum += numDecodings(tail);
}
return sum;
}
Cached Recursive Implementation
Obviously this isn't very efficient, because (for longer ETs), the same tail will be analyzed multiple times. Also, we create a lot of temporary strings, but we'll let that be for now. One thing we can easily do is to memoize the number of decodings of a specific tail. For that, we use an array of the same length as the input string:
static final int upperLimit = 26;
static final int maxHeadSize = ("" + upperLimit).length();
static int numDecodings(String encodedText) {
return numDecodings(encodedText, new Integer[1 + encodedText.length()]);
}
static int numDecodings(String encodedText, Integer[] cache) {
// check base case for the recursion
if (encodedText.length() == 0) {
return 1;
}
// check if this tail is already known in the cache
if (cache[encodedText.length()] != null) {
return cache[encodedText.length()];
}
// cache miss -- sum all tails
int sum = 0;
for (int headSize = 1; headSize <= maxHeadSize && headSize <= encodedText.length(); headSize++) {
String head = encodedText.substring(0, headSize);
String tail = encodedText.substring(headSize);
if (Integer.parseInt(head) > upperLimit) {
break;
}
sum += numDecodings(tail, cache); // pass the cache through
}
// update the cache
cache[encodedText.length()] = sum;
return sum;
}
Note that we use an Integer[], not an int[]. This way, we can check for non-existent entries using a test for null. This solution is not only correct, it is also comfortably fast – naive recursion runs in O(number of decodings) time, while the memoized version runs in O(string length) time.
Towards a DP Solution
When you run above code in your head, you will notice that the first invocation with the whole string will have a cache miss, then calculate the number of decodings for the first tail, which also misses the cache every time. We can avoid this by evaluating the tails first, starting from the end of the input. Because all tails will have been evaluated before the whole string is, we can remove the checks for cache misses. Now we also don't have any reason for recursion, because all previous results are already in the cache.
static final int upperLimit = 26;
static final int maxHeadSize = ("" + upperLimit).length();
static int numDecodings(String encodedText) {
int[] cache = new int[encodedText.length() + 1];
// base case: the empty string at encodedText.length() is 1:
cache[encodedText.length()] = 1;
for (int position = encodedText.length() - 1; position >= 0; position--) {
// sum directly into the cache
for (int headSize = 1; headSize <= maxHeadSize && headSize + position <= encodedText.length(); headSize++) {
String head = encodedText.substring(position, position + headSize);
if (Integer.parseInt(head) > upperLimit) {
break;
}
cache[position] += cache[position + headSize];
}
}
return cache[0];
}
This algorithm could be optimized further by noticing that we only ever query the last maxHeadSize elements in the cache. So instead of an array, we could use a fixed-sized queue. At that point, we would have a dynamic programming solution that runs in *O(input length) time and O(maxHeadSize) space.
Specialization for upperLimit = 26
The above algorithms were kept as general as possible, but we can go and manually specialize it for a specific upperLimit. This can be useful because it allows us to do various optimizations. However, this introduces “magic numbers” that make the code harder to maintain. Such manual specializations should therefore be avoided in non-critical software (and the above algorithm is already as fast as it gets).
static int numDecodings(String encodedText) {
// initialize the cache
int[] cache = {1, 0, 0};
for (int position = encodedText.length() - 1; position >= 0; position--) {
// rotate the cache
cache[2] = cache[1];
cache[1] = cache[0];
cache[0] = 0;
// headSize == 1
if (position + 0 < encodedText.length()) {
char c = encodedText.charAt(position + 0);
// 1 .. 9
if ('1' <= c && c <= '9') {
cache[0] += cache[1];
}
}
// headSize == 2
if (position + 1 < encodedText.length()) {
char c1 = encodedText.charAt(position + 0);
char c2 = encodedText.charAt(position + 1);
// 10 .. 19
if ('1' == c1) {
cache[0] += cache[2];
}
// 20 .. 26
else if ('2' == c1 && '0' <= c2 && c2 <= '6') {
cache[0] += cache[2];
}
}
}
return cache[0];
}
Comparision with your code
The code is superficially similar. However, your parsing around characters is more convoluted. You have introduced a used variable that, if set, will decrement the decode count in order to account for double-character CPs. This is wrong, but I am not sure why. The main problem is that you are doubling the count at almost every step. As we have seen, the previous counts are added, and may very well be different.
This indicates that you wrote the code without proper preparation. You can write many kinds of software without having to think too much, but you can't do without careful analysis when designing an algorithm. For me, it is often helpful to design an algorithm on paper, and draw diagrams of each step (along the lines of the “Theoretical Prelude” of this answer). This is especially useful when you are thinking too much about the language you are going to implement in, and too little about possibly wrong assumptions.
I suggest that you read up on “proofs by induction” to understand how to write a correct recursive algorithm. Once you have a recursive solution, you can always translate it into an iterative version.
So here is some what simpler way out for your problem. This is pretty close to calculating Fibonacci, with the difference that there are condition checks on each smaller size subproblem.
The space complexity is O(1) and time is O(n)
The code is in C++.
int numDecodings(string s)
{
if( s.length() == 0 ) return 0;
int j = 0;
int p1 = (s[j] != '0' ? 1 : 0); // one step prev form j=1
int p2 = 1; // two step prev from j=1, empty
int p = p1;
for( int j = 1; j < s.length(); j++ )
{
p = 0;
if( s[j] != '0' )
p += p1;
if( isValidTwo(s, j-1, j) )
p += p2;
if( p==0 ) // no further decoding necessary,
break; // as the prefix 0--j is has no possible decoding.
p2 = p1; // update prev for next j+1;
p1 = p;
}
return p;
}
bool isValidTwo(string &s, int i, int j)
{
int val= 10*(s[i]-'0')+s[j]-'0';
if ( val <= 9 )
return false;
if ( val > 26 )
return false;
return true;
}
Here is my code to solve the problem. I use DP , I think it's clear to understand.
Written in Java
public class Solution {
public int numDecodings(String s) {
if(s == null || s.length() == 0){
return 0;
}
int n = s.length();
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = s.charAt(0) != '0' ? 1 : 0;
for(int i = 2; i <= n; i++){
int first = Integer.valueOf(s.substring(i-1,i));
int second = Integer.valueOf(s.substring(i-2,i));
if(first >= 1 && first <= 9){
dp[i] += dp[i-1];
}
if(second >= 10 && second <= 26){
dp[i] += dp[i-2];
}
}
return dp[n];
}
}
Since I struggled with this problem myself, here is my solution and reasoning. Probably I will mostly repeat what amon wrote, but maybe someone will find it helpful. Also it's c# not java.
Let's say that we have input "12131" and want to obtain all possible decoded strings.
Straightforward recursive solution would do iterate from left to right, obtain valid 1 and 2 digits heads, and invoke function recursively for tail.
We can visualize it using a tree:
There are 5 leaves and this is number of all possible decoded strings. There are also 3 empty leaves, because number 31 cannot be decoded into letter, so these leaves are invalid.
Algorithm might look like this:
public IList<string> Decode(string s)
{
var result = new List<string>();
if (s.Length <= 2)
{
if (s.Length == 1)
{
if (s[0] != '0')
result.Add(this.ToASCII(s));
}
else if (s.Length == 2)
{
if (s[0] != '0' && s[1] != '0')
result.Add(this.ToASCII(s.Substring(0, 1)) + this.ToASCII(s.Substring(1, 1)));
if (s[0] != '0' && int.Parse(s) > 0 && int.Parse(s) <= 26)
result.Add(this.ToASCII(s));
}
}
else
{
for (int i = 1; i <= 2; ++i)
{
string head = s.Substring(0, i);
if (head[0] != '0' && int.Parse(head) > 0 && int.Parse(head) <= 26)
{
var tails = this.Decode(s.Substring(i));
foreach (var tail in tails)
result.Add(this.ToASCII(head) + tail);
}
}
}
return result;
}
public string ToASCII(string str)
{
int number = int.Parse(str);
int asciiChar = number + 65 - 1; // A in ASCII = 65
return ((char)asciiChar).ToString();
}
We have to take care of numbers starting with 0 ("0", "03", etc.), and greater than 26.
Because in this problem we need only count decoding ways, and not actual strings, we can simplify this code:
public int DecodeCount(string s)
{
int count = 0;
if (s.Length <= 2)
{
if (s.Length == 1)
{
if (s[0] != '0')
count++;
}
else if (s.Length == 2)
{
if (s[0] != '0' && s[1] != '0')
count++;
if (s[0] != '0' && int.Parse(s) > 0 && int.Parse(s) <= 26)
count++;
}
}
else
{
for (int i = 1; i <= 2; ++i)
{
string head = s.Substring(0, i);
if (head[0] != '0' && int.Parse(head) > 0 && int.Parse(head) <= 26)
count += this.DecodeCount(s.Substring(i));
}
}
return count;
}
The problem with this algorithm is that we compute results for the same input string multiple times. For example there are 3 nodes ending with 31: ABA31, AU31, LA31. Also there are 2 nodes ending with 131: AB131, L131.
We know that if node ends with 31 it has only one child, since 31 can be decoded only in one way to CA. Likewise, we know that if string ends with 131 it has 2 children, because 131 can be decoded into ACA or LA. Thus, instead of computing it all over again we can cache it in map, where key is string (eg: "131"), and value is number of decoded ways:
public int DecodeCountCached(string s, Dictionary<string, int> cache)
{
if (cache.ContainsKey(s))
return cache[s];
int count = 0;
if (s.Length <= 2)
{
if (s.Length == 1)
{
if (s[0] != '0')
count++;
}
else if (s.Length == 2)
{
if (s[0] != '0' && s[1] != '0')
count++;
if (s[0] != '0' && int.Parse(s) > 0 && int.Parse(s) <= 26)
count++;
}
}
else
{
for (int i = 1; i <= 2; ++i)
{
string head = s.Substring(0, i);
if (head[0] != '0' && int.Parse(head) > 0 && int.Parse(head) <= 26)
count += this.DecodeCountCached(s.Substring(i), cache);
}
}
cache[s] = count;
return count;
}
We can refine this even further. Instead of using strings as a keys, we can use length, because what is cached is always tail of input string. So instead of caching strings: "1", "31", "131", "2131", "12131" we can cache lengths of tails: 1, 2, 3, 4, 5:
public int DecodeCountDPTopDown(string s, Dictionary<int, int> cache)
{
if (cache.ContainsKey(s.Length))
return cache[s.Length];
int count = 0;
if (s.Length <= 2)
{
if (s.Length == 1)
{
if (s[0] != '0')
count++;
}
else if (s.Length == 2)
{
if (s[0] != '0' && s[1] != '0')
count++;
if (s[0] != '0' && int.Parse(s) > 0 && int.Parse(s) <= 26)
count++;
}
}
else
{
for (int i = 1; i <= 2; ++i)
{
string head = s.Substring(0, i);
if (s[0] != '0' && int.Parse(head) > 0 && int.Parse(head) <= 26)
count += this.DecodeCountDPTopDown(s.Substring(i), cache);
}
}
cache[s.Length] = count;
return count;
}
This is recursive top-down dynamic programming approach. We start from the begining, and then recursively compute solutions for tails, and memoize those results for further use.
We can translate it to bottom-up iterative DP solution. We start from the end and cache results for tiles like in previous solution. Instead of map we can use array because keys are integers:
public int DecodeCountBottomUp(string s)
{
int[] chache = new int[s.Length + 1];
chache[0] = 0; // for empty string;
for (int i = 1; i <= s.Length; ++i)
{
string tail = s.Substring(s.Length - i, i);
if (tail.Length == 1)
{
if (tail[0] != '0')
chache[i]++;
}
else if (tail.Length == 2)
{
if (tail[0] != '0' && tail[1] != '0')
chache[i]++;
if (tail[0] != '0' && int.Parse(tail) > 0 && int.Parse(tail) <= 26)
chache[i]++;
}
else
{
if (tail[0] != '0')
chache[i] += chache[i - 1];
if (tail[0] != '0' && int.Parse(tail.Substring(0, 2)) > 0 && int.Parse(tail.Substring(0, 2)) <= 26)
chache[i] += chache[i - 2];
}
}
return chache.Last();
}
Some people simplify it even further, initializing cache[0] with value 1, so they can get rid of conditions for tail.Length==1 and tail.Length==2. For me it is unintuitive trick though, since clearly for empty string there is 0 decode ways not 1, so in such case additional condition must be added to handle empty input:
public int DecodeCountBottomUp2(string s)
{
if (s.Length == 0)
return 0;
int[] chache = new int[s.Length + 1];
chache[0] = 1;
chache[1] = s.Last() != '0' ? 1 : 0;
for (int i = 2; i <= s.Length; ++i)
{
string tail = s.Substring(s.Length - i, i);
if (tail[0] != '0')
chache[i] += chache[i - 1];
if (tail[0] != '0' && int.Parse(tail.Substring(0, 2)) > 0 && int.Parse(tail.Substring(0, 2)) <= 26)
chache[i] += chache[i - 2];
}
return chache.Last();
}
My solution is based on the idea that the arrangement of items(char/digit) within a particular substring is completely independent of the same within a different substring.
So we need to multiply each of those independent ways to get the total number of ways.
// nc is the number of consecutive 1's or 2's in a substring.
// Returns the number of ways these can be arranged within
// themselves to a valid expr.
int ways(int nc){
int n = pow(2, (nc/2)); //this part can be memorized using map for optimization
int m = n;
if (nc%2) {
m *= 2;
}
return n + m - 1;
}
bool validTens(string A, int i){
return (A[i] == '1' || (A[i] == '2' && A[i+1] <= '6'));
}
int numDecodings(string A) {
int ans = 1;
int nc;
if ((A.length() == 0)||(A[0] == '0')) return 0;
for(int i = 1; i < A.length();i++){
if(A[i] == '0' && validTens(A, i-1) == false) return 0; //invalid string
while(i < A.length() && validTens(A, i-1)) {
if(A[i] == '0'){
//think of '110' or '1210', the last two digits must be together
if(nc > 0) nc--;
}
else nc++;
i++;
}
ans *= ways(nc);
nc = 0;
}
return ans;
}
Java solution with space and time complexity O(n)
public int numDecodings(String s) {
int n = s.length();
if (n > 0 && s.charAt(0) == '0')
return 0;
int[] d = new int[n + 1];
d[0] = 1;
d[1] = s.charAt(0) != '0' ? 1 : 0;
for (int i = 2; i <= n; i++) {
if (s.charAt(i - 1) > '0')
d[i] = d[i] + d[i - 1];
if (s.charAt(i - 2) == '2' && s.charAt(i - 1) < '7')
d[i] = d[i - 2] + d[i];
if (s.charAt(i - 2) == '1' && s.charAt(i - 1) <= '9')
d[i] = d[i - 2] + d[i];
}
return d[n];
}
Here is an O(N) C++ DP implementation.
int numDecodings(string s) {
if(s[0] == '0') return 0; // Invalid Input
int n = s.length();
// dp[i] denotes the number of ways to decode the string of length 0 to i
vector<int> dp(n+1, 0);
// base case : string of 0 or 1 characters will have only 1 way to decode
dp[0] = dp[1] = 1;
for(int i = 2; i <= n; i++) {
// considering the previous number
if(s[i-1] > '0') dp[i] += dp[i-1];
// considering the previous two numbers
if(s[i-2] == '1' || (s[i-2] == '2' && s[i-1] < '7')) dp[i] += dp[i-2];
}
return dp[n];
}

Unexpected behaviour of code while executing program for specific test cases.(in Java)

Here's a piece of code that I've written to check if the sum of digits and sum of squares of digits of a number are prime,in a given range. If they both are prime, I simply increment the counter, and ultimately I print the counter value.
for(int j = lb; j <= ub ; j++)
{
temp = j;
do
{
sd = sd + (temp%10);
sosd = sosd + ((temp%10) * (temp%10));
temp = temp/10;
}while( temp != 0);
for(int p = 2; p <= (sd/2) ; p++)
{
if( p == sd/2 )
pf = 0;
if( sd % p == 0 )
{
pf = 1;
break;
}
}
for(int p = 2; p <= (sosd/2) ; p++)
{
if( p == sosd/2 )
pff = 0;
if( sosd % p == 0 )
{
pff = 1;
break;
}
}
if( pf == 0 && pff == 0 )
count++;
sd = 0;
sosd = 0;
}
System.out.println(count);
All the variables have been properly defined and declared(please bear with the variable names).
The problem is : when I run for lb = 10 to ub = 20, I get count = 4 (which is correct).
But when I run for lb = 1 to ub = 20 , I get count = 3(It is wrong!! And I'm unable to find how this is so,I tried printing individual values only to find that there is something wrong with count and it doesn't increment for the last time. And much to my astonishment, it produces the right answer for the first case that I tested, which is a subset of this case! ).
Please help!
It would be better and easier to analyze the code with adding proper methods which clearly give a hint on what they are doing. that will remove the need to rely on the global variables in such a dangerous way where they need resetting in the loops, something we tend to forget.
define three methods: one to sum the digits, one to sum the squares of digits and one to check if a number is prime. after that, finding bugs is easier as you will debug single methods.
check the following rewrite:
static int sumOfDigits(int number){
int sum = 0;
while (number != 0) {
sum += number % 10;
number /= 10;
}
return sum;
}
static int sumOfSquaresOfDigits(int number){
int sum = 0;
int digit=0;
while (number != 0) {
digit=number % 10;
sum += digit*digit;
number /= 10;
}
return sum;
}
static boolean isPrime(int number) {
//check if n is a multiple of 2
if (number%2==0) return false;
//if not, then just check the odds
for(int i=3;i*i<=number;i+=2) {
if(number%i==0)
return false;
}
return true;
}
now that those methods are defined, the code becomes like this:
int count=0;
int lb=1;
int ub=20;
for(int j = lb; j <= ub ; j++)
if ( isPrime(sumOfDigits(j)) && isPrime(sumOfSquaresOfDigits(j)) )
count++;
System.out.println(count);
Note: code for summing digits was taken from here and i modified it to make version for summing squares.
code for checking prime was taken from here
The problem lies in the two inner for loops:
for (int p = 2; p <= (sd/2) ; p++)
{
if( p == sd/2 )
pf = 0;
In some cases, p would not necessarily reach sd/2 which means that the pf variable would not reset to 0. Simply try reseting pf and pff to 0 at the end of your outermost for loop:
pf = 0;
pff = 0;
EDIT:
Here's the modification to your code that seems to work fine for me:
for (int j = lb; j <= ub; j++) {
sd = 0;
sosd = 0;
pf = 0;
pff = 0;
temp = j;
do {
sd = sd + (temp % 10);
sosd = sosd + ((temp % 10) * (temp % 10));
temp = temp / 10;
} while (temp != 0);
// Check for 1
if (sd == 1 || sosd == 1) continue;
for (int p = 2; p <= (sd / 2); p++) {
if (p == sd / 2) {
pf = 0;
}
if (sd % p == 0) {
pf = 1;
break;
}
}
for (int p = 2; p <= (sosd / 2); p++) {
if (p == sosd / 2) {
pff = 0;
}
if (sosd % p == 0) {
pff = 1;
break;
}
}
if (pf == 0 && pff == 0) {
count++;
}
}
System.out.println(count);
Btw to check for the primality of a number n, you can run the loop upto sqrt(n) instead of n/2. This will improve the efficiency for testing larger numbers. sqrt(n) is a stricter bound.

Categories

Resources