What is wrong with my Floyd Warshall algorithm? - java

Here is the problem link
Approach:
My approach is to simply give every other node the chance to be an in-between node for every 2 pairs of vertices i and j.
Below is my code for Floyd Warshall algorithm:
class Solution{
public void shortest_distance(int[][] mat){
int N = mat.length;
for(int i = 0; i < N; ++i){
for(int j = 0; j < N; ++ j){
for(int k = 0; k < N; ++k){
if(mat[i][k] != -1 && mat[k][j] != -1 && (mat[i][j] == -1 || mat[i][j] > mat[i][k] + mat[k][j])){
mat[i][j] = mat[i][k] + mat[k][j];
}
}
}
}
}
}
This gives wrong answer for the below case:
Input
12
0 4 2 1 2 9 4 8 -1 4 -1 -1
9 0 3 6 2 6 2 3 6 -1 -1 3
7 1 0 10 8 9 1 3 -1 7 -1 10
5 1 9 0 3 -1 1 10 7 1 -1 7
-1 5 1 4 0 2 10 4 10 6 4 5
7 8 3 7 5 0 5 1 3 5 7 2
6 -1 6 1 10 7 0 10 -1 -1 7 7
-1 3 2 7 4 -1 4 0 10 5 6 10
10 6 1 10 4 4 7 10 0 4 7 4
1 1 6 8 8 9 2 10 6 0 -1 3
5 9 3 -1 4 3 -1 -1 -1 3 0 1
2 2 8 6 2 4 4 3 -1 3 4 0
My output
0 2 2 1 2 4 2 5 7 2 6 5
5 0 3 3 2 4 2 3 6 4 6 3
6 1 0 2 3 5 1 3 7 3 7 4
2 1 4 0 3 5 1 4 7 1 7 4
6 2 1 3 0 2 2 3 5 4 4 4
4 4 3 5 4 0 4 1 3 5 6 2
3 2 5 1 4 6 0 5 8 2 7 5
6 3 2 4 4 6 3 0 9 5 6 6
5 2 1 3 4 4 2 4 0 4 7 4
1 1 3 2 3 5 2 4 6 0 7 3
3 3 3 4 3 3 4 4 6 3 0 1
2 2 3 3 2 4 4 3 7 3 4 0
Expected Output
0 2 2 1 2 4 2 5 7 2 6 5
5 0 3 3 2 4 2 3 6 4 6 3
4 1 0 2 3 5 1 3 7 3 7 4
2 1 4 0 3 5 1 4 7 1 7 4
5 2 1 3 0 2 2 3 5 4 4 4
4 4 3 5 4 0 4 1 3 5 6 2
3 2 5 1 4 6 0 5 8 2 7 5
6 3 2 4 4 6 3 0 9 5 6 6
5 2 1 3 4 4 2 4 0 4 7 4
1 1 3 2 3 5 2 4 6 0 7 3
3 3 3 4 3 3 4 4 6 3 0 1
2 2 3 3 2 4 4 3 7 3 4 0
Note: I have also observed that if I move the k loop out and make it the first loop, it works just fine. I am confused as to what is wrong with my current code.

It is all about states. This is more conceptual than any algorithmic implementation issue here.
As in your code,
for(i...)
for(j..)
for(k...)
mat[i][j] = mat[i][k] + mat[k][j];
The above states, for every pair of nodes i and j, check if any shortest path exists via every possible k. However, you are implicitly assuming that mat[i][k] and mat[k][j] are in already optimized states. This is incorrect as there is no real effort made in the code to bring them to that state.
Instead, you need to check for every pair of nodes i and j via only 1 value of k at a time. This is how you would be building the optimized states for every possible k one by one and the next one depending on the previous one. Hence, the below is correct version for this:
class Solution{
public void shortest_distance(int[][] mat){
int N = mat.length;
for(int k = 0; k < N; ++k){
for(int i = 0; i < N; ++i){
for(int j = 0; j < N; ++j){
if(mat[i][k] != -1 && mat[k][j] != -1 && (mat[i][j] == -1 || mat[i][j] > mat[i][k] + mat[k][j])){
mat[i][j] = mat[i][k] + mat[k][j];
}
}
}
}
}
}
Quoting from the Wiki.
The Floyd–Warshall algorithm compares all possible paths through the
graph between each pair of vertices. It is able to do this with
{\displaystyle \Theta (|V|^{3})}\Theta (|V|^{3}) comparisons in a
graph, even though there may be up to {\displaystyle \Omega
(|V|^{2})}{\displaystyle \Omega (|V|^{2})} edges in the graph, and
every combination of edges is tested. It does so by incrementally
improving an estimate on the shortest path between two vertices, until
the estimate is optimal.
Miscellaneous:
Although trivial, but I still think it is worth mentioning that the order of nodes used in the optimization process really doesn't matter. We simply need to shorten the distance(if exists and possible) node by node where every node is an intermediate candidate.
class Solution{
public void shortest_distance(int[][] mat){
int N = mat.length;
List<Integer> nodes = new ArrayList<>();
for(int i = 0; i < N; ++i) nodes.add(i);
Collections.shuffle(nodes);
for(int l = 0; l < nodes.size(); ++l){
int k = nodes.get(l);
for(int i = 0; i < N; ++i){
for(int j = 0; j < N; ++j){
if(mat[i][k] != -1 && mat[k][j] != -1 && (mat[i][j] == -1 || mat[i][j] > mat[i][k] + mat[k][j])){
mat[i][j] = mat[i][k] + mat[k][j];
}
}
}
}
}
}

Related

Bubble sort with output

So I have edited it some and am getting almost exactly what I want. The only problem I am having now is that I am getting a line of output that I don't want. I feel like the fix here is simple but my brain is fried right now.
static void bubbleSort(int[] myArray) {
int n = myArray.length;
int temp = 0;
int counter = 0;
for (int i = 0; i < n; i++) {
int k;
for (k = 0; k < n; k++) {
System.out.print(myArray[k] + "|");
}
System.out.println(" Num swaps: " + counter);
for (int j = 1; j < (n - i); j++) {
if (myArray[j - 1] > myArray[j]) {
//swap elements
temp = myArray[j - 1];
myArray[j - 1] = myArray[j];
myArray[j] = temp;
counter++;
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] myArray = new int[10];
for (int i = 0; i < 10; i++) {
System.out.print("Enter slot " + i + ": ");
myArray[i] = sc.nextInt();
}
bubbleSort(myArray);
}
Here is an example of what I get:
Enter slot 0: 10
Enter slot 1: 9
Enter slot 2: 8
Enter slot 3: 7
Enter slot 4: 6
Enter slot 5: 5
Enter slot 6: 4
Enter slot 7: 3
Enter slot 8: 2
Enter slot 9: 1
10|9|8|7|6|5|4|3|2|1| Num swaps: 0
9|8|7|6|5|4|3|2|1|10| Num swaps: 9
8|7|6|5|4|3|2|1|9|10| Num swaps: 17
7|6|5|4|3|2|1|8|9|10| Num swaps: 24
6|5|4|3|2|1|7|8|9|10| Num swaps: 30
5|4|3|2|1|6|7|8|9|10| Num swaps: 35
4|3|2|1|5|6|7|8|9|10| Num swaps: 39
3|2|1|4|5|6|7|8|9|10| Num swaps: 42
2|1|3|4|5|6|7|8|9|10| Num swaps: 44
1|2|3|4|5|6|7|8|9|10| Num swaps: 45
That first line of output where it just repeats what the user input and says 0 swaps. I don't want that.
Just changed the position of the for loops. Hope this is the output you actually want :).
static void bubbleSort(int[] myArray) {
int n = myArray.length;
int temp = 0;
int counter = 0;
for (int i = 0; i < n; i++) {
for (int j = 1; j < (n - i); j++) {
if (myArray[j - 1] > myArray[j]) {
// swap elements
temp = myArray[j - 1];
myArray[j - 1] = myArray[j];
myArray[j] = temp;
counter++;
}
}
int k;
for (k = 0; k < n; k++) {
System.out.print(myArray[k] + "|");
}
System.out.println(" Num swaps: " + counter);
}
}
Algorithm with two nested streams: Bubble sort with step-by-step output Java 8
Bubble sort with step-by-step output
The outer do-while-loop repeats until the array is sorted, and the inner for-loop passes through the array, swapping the unordered adjacent elements. The output is the swapped elements in the inner loop, grouped by passes in the outer loop.
public static void main(String[] args) {
int[] arr = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
bubbleSort(arr);
}
public static void bubbleSort(int[] arr) {
// counters
int passes = 0, swaps = 0;
// marker
boolean swapped;
// repeat the passes through the array until
// all the elements are in the correct order
do {
// output the beginning of the pass and increase the counter of passes
System.out.print((passes == 0 ? "<pre>" : "<br>") + "Pass: " + passes++);
swapped = false;
// pass through the array and
// compare adjacent elements
for (int i = 0; i < arr.length - 1; i++) {
// if this element is greater than
// the next one, then swap them
if (arr[i] > arr[i + 1]) {
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
swapped = true;
// output the array and increase the counter of swaps
System.out.print(outputSwapped(arr, i, i + 1, swaps++));
}
}
// if there are no swapped elements at the
// current pass, then this is the last pass
} while (swapped);
// output total
System.out.print("<br>Total: Passes=" + passes);
System.out.println(", swaps=" + swaps + "</pre>");
}
static String outputSwapped(int[] arr, int e1, int e2, int counter) {
StringBuilder sb = new StringBuilder("<br>");
for (int i = 0; i < arr.length; i++) {
if (i == e1 || i == e2) {
// swapped elements are in bold
sb.append("<b>").append(arr[i]).append("</b>");
} else {
// other elements
sb.append(arr[i]);
}
sb.append(" ");
}
return sb.append("| ").append(counter).toString();
}
Output:
Pass: 09 10 8 7 6 5 4 3 2 1 | 09 8 10 7 6 5 4 3 2 1 | 19 8 7 10 6 5 4 3 2 1 | 29 8 7 6 10 5 4 3 2 1 | 39 8 7 6 5 10 4 3 2 1 | 49 8 7 6 5 4 10 3 2 1 | 59 8 7 6 5 4 3 10 2 1 | 69 8 7 6 5 4 3 2 10 1 | 79 8 7 6 5 4 3 2 1 10 | 8Pass: 18 9 7 6 5 4 3 2 1 10 | 98 7 9 6 5 4 3 2 1 10 | 108 7 6 9 5 4 3 2 1 10 | 118 7 6 5 9 4 3 2 1 10 | 128 7 6 5 4 9 3 2 1 10 | 138 7 6 5 4 3 9 2 1 10 | 148 7 6 5 4 3 2 9 1 10 | 158 7 6 5 4 3 2 1 9 10 | 16Pass: 27 8 6 5 4 3 2 1 9 10 | 177 6 8 5 4 3 2 1 9 10 | 187 6 5 8 4 3 2 1 9 10 | 197 6 5 4 8 3 2 1 9 10 | 207 6 5 4 3 8 2 1 9 10 | 217 6 5 4 3 2 8 1 9 10 | 227 6 5 4 3 2 1 8 9 10 | 23Pass: 36 7 5 4 3 2 1 8 9 10 | 246 5 7 4 3 2 1 8 9 10 | 256 5 4 7 3 2 1 8 9 10 | 266 5 4 3 7 2 1 8 9 10 | 276 5 4 3 2 7 1 8 9 10 | 286 5 4 3 2 1 7 8 9 10 | 29Pass: 45 6 4 3 2 1 7 8 9 10 | 305 4 6 3 2 1 7 8 9 10 | 315 4 3 6 2 1 7 8 9 10 | 325 4 3 2 6 1 7 8 9 10 | 335 4 3 2 1 6 7 8 9 10 | 34Pass: 54 5 3 2 1 6 7 8 9 10 | 354 3 5 2 1 6 7 8 9 10 | 364 3 2 5 1 6 7 8 9 10 | 374 3 2 1 5 6 7 8 9 10 | 38Pass: 63 4 2 1 5 6 7 8 9 10 | 393 2 4 1 5 6 7 8 9 10 | 403 2 1 4 5 6 7 8 9 10 | 41Pass: 72 3 1 4 5 6 7 8 9 10 | 422 1 3 4 5 6 7 8 9 10 | 43Pass: 81 2 3 4 5 6 7 8 9 10 | 44Pass: 9Total: Passes=10, swaps=45
See also: Bubble sort output is incorrect

How to: square root squares for cosine similarity within an array ~java~

My issue is that I have am creating a book recommendation system and when I try to square root the squares to determine similarity. I do not believe it is square rooting all the contents of each array.
The user is prompted with the twenty books and then inputs answers ranging from '1-5' based on how much they like the book and '-1' if they have not read the book.
A few of my score outputs are NaN. Therefore I assume it is just stopping after the first element of the array.
I have tried rearranging loops I personally think it is an issue with the loops and how it accesses the array.
Here is
CPU ratings file.
-1 1 1 4 1 3 3 1 2 3 4 -1 4 1 2 4 5 4 2 3
3 -1 2 3 -1 2 5 -1 3 3 5 2 2 1 2 3 5 3 4 2
-1 1 -1 4 1 3 5 2 1 5 3 -1 5 2 1 3 4 5 3 2
-1 -1 3 2 -1 5 5 2 2 4 4 2 3 2 -1 3 4 4 3 1
2 1 1 5 2 2 4 2 3 4 3 -1 5 2 2 5 3 5 2 1
3 -1 3 4 -1 2 5 -1 -1 4 3 -1 3 -1 2 5 5 5 4 2
4 -1 4 2 3 -1 1 3 4 -1 1 4 4 4 -1 2 -1 1 4 4
4 3 3 3 -1 2 2 4 3 -1 2 4 3 4 2 -1 -1 2 2 3
3 -1 3 -1 3 4 -1 5 5 -1 -1 -1 1 -1 -1 1 1 2 -1 5
3 -1 3 4 3 4 -1 5 5 2 3 3 4 1 1 -1 -1 -1 -1 4
4 -1 4 4 1 3 -1 5 4 -1 1 3 4 1 -1 1 -1 1 -1 5
5 -1 3 1 4 3 -1 5 4 1 3 2 1 -1 4 2 1 -1 2 4
3 -1 5 1 4 4 2 5 5 1 2 3 1 1 -1 1 -1 1 -1 5
4 1 5 4 3 -1 1 3 4 -1 -1 3 3 -1 1 1 2 -1 3 5
-1 1 1 3 -1 3 1 3 -1 -1 3 -1 5 2 2 1 4 -1 5 -1
3 -1 2 3 1 5 4 3 3 -1 5 -1 5 2 -1 4 4 3 3 3
1 1 1 3 2 4 1 -1 -1 -1 5 -1 3 -1 -1 1 -1 2 5 2
-1 2 3 5 -1 4 3 1 1 3 3 -1 4 -1 -1 4 3 2 5 1
-1 1 3 3 -1 3 3 1 -1 -1 3 -1 5 -1 -1 3 1 2 4 -1
3 -1 2 4 1 4 3 -1 2 3 4 1 3 -1 2 -1 4 3 5 -1
-1 1 3 5 -1 4 2 1 -1 3 3 2 3 2 -1 3 1 -1 3 -1
3 2 2 3 -1 5 -1 -1 2 3 4 -1 4 1 -1 -1 -1 -1 4 2
-1 3 -1 -1 4 -1 2 -1 2 2 2 5 -1 3 4 -1 -1 2 -1 2
1 4 3 -1 3 2 1 -1 -1 -1 1 3 1 3 3 1 -1 -1 -1 3
4 3 3 -1 4 2 -1 4 -1 -1 2 4 -1 3 4 2 -1 -1 -1 4
-1 5 1 -1 4 1 -1 3 2 2 -1 4 1 3 3 1 -1 -1 -1 3
-1 4 2 1 5 -1 -1 2 1 1 -1 5 -1 5 4 1 2 2 -1 1
2 5 2 -1 3 -1 -1 1 -1 2 -1 4 2 4 3 -1 2 1 -1 -1
2 5 1 1 4 -1 2 1 -1 -1 2 4 -1 3 4 2 -1 -1 -1 4
method to square root the squares
public static double sqrtSquares(double []A) {
//check A for -1
double sum = 0;
for(int i = 0; i<A.length; i++) {
if(A[i] < 0 ) {
A[i] = 0;
}
A[i] = Math.sqrt(A[i]);
//calculate the running sum;
sum += A[i] * A[i] ;
}
return Math.sqrt(sum);
}
public static double similarity(double []A, double []B) {
double sum = 0;
double p1 = sqrtSquares(A);
double p2 = sqrtSquares(B);
for (int i=0; i<A.length; i++) {
if (A[i]> 0) {
if (B[i]> 0) {
sum += A[i]*B[i];
}
}
}
return sum/(p1*p2);
}
here is the main similarity score method
double []scores = new double[30];
for(int i = 0; i< 30; i++) {
scores[i] = similarity(yourrating, pplratings[i]);
}
for(int k = 0; k <scores.length; k++) {
System.out.println("SCORES ["+ k + "] "+scores[k]);
}
return scores;
}
In the end of the method it prints the 30 scores retrieved by both of the arrays. Here are the error results
SCORES [0] 0.8345932239467343
SCORES [1] 0.8930284538287845
SCORES [2] 0.8859571865530889
SCORES [3] 0.8885782312086968
SCORES [4] 0.8775173350115371
SCORES [5] 0.9443223415026459
SCORES [6] 0.8250453876017286
SCORES [7] 0.8432290780758503
SCORES [8] 0.8862288358972311
SCORES [9] 0.7131697319344704
SCORES [10] 0.8182594818515688
SCORES [11] 0.8009904274635006
SCORES [12] 0.8637068116707501
SCORES [13] 0.8507371827482269
SCORES [14] 0.8370334932826162
SCORES [15] 0.775738787468209
SCORES [16] 0.880315376993314
SCORES [17] 0.7702419338621114
SCORES [18] 0.841428935139835
SCORES [19] 0.7527243233023518
SCORES [20] 0.8474342113753683
SCORES [21] 0.815084547094269
SCORES [22] 0.7592956404693546
SCORES [23] 0.7303452808509205
SCORES [24] 0.7808981699861455
SCORES [25] 0.7676319325573738
SCORES [26] 0.7782147276497292
SCORES [27] 0.7962287074180334
SCORES [28] 0.7538710355467405
SCORES [29] 0.7795507063811014
EDIT: this code now works. Thank you for everyone's help.
public static double sqrtSquares(double []A) {
double sum = 0;
for(int i = 0; i<A.length; i++) {
if(A[i] < 0 ) {
A[i] = 0;
}
sum += A[i]*A[i]; // calculate the running sum of squares
}
return Math.sqrt(sum);
}
Based on cosine-similarity definition: https://en.wikipedia.org/wiki/Cosine_similarity
From our discussion, and your explanation of the problem, the following issues were found in your code.
The logic in the sqrtSquares() function was flawed. It still needs correction because you are implementing cosine similarity. The right definition is provided by #hsin1.att214. I am writing it here again, for convenience:
public static double sqrtSquares(double []A) {
double sum = 0;
for(int i = 0; i<A.length; i++) {
if(A[i] < 0 ) {
A[i] = 0;
}
sum += A[i]*A[i]; // calculate the running sum of squares
}
return Math.sqrt(sum); // calculate the square root of the sum of squares
}
The use of two return statements, one of which was inside the for loop, returns values after processing just the first element of the array. So pull the return statement outside the loop.

How can I space my triangle correctly?

I am trying to print out a Right Triangle that looks like this:
1
2 1
3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
11 10 9 8 7 6 5 4 3 2 1
The size of the triangle increases if the number in the method gets larger, which in this case is 11.
My code seems to only work up to 10 as after 10, my spacing is messed up.
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
11 10 9 8 7 6 5 4 3 2 1
12 11 10 9 8 7 6 5 4 3 2 1
13 12 11 10 9 8 7 6 5 4 3 2 1
I am trying to make it so that up to 99, the spacing is correct. What kind of edits should I do to my if statements or for loops in order to space it properly?
Code:
public class Patterns
{
public static void main(String[] args)
{
displayPattern(13);
//displayPattern(11,",");
}
public static void displayPattern(int n)
{
//print out n-1 spaces and the first number
//print n-2 spaces and the 2nd then first number
int counter = n;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= counter; j++)
{
if (n > 10)
{
if (i == n)
{
System.out.print("");
}
else if (i <= 10)
{
System.out.print(" ");
}
else
{
System.out.print(" ");
}
}
else if (n <=10)
{
if (i>9)
{
System.out.print(" ");
}
else
{
System.out.print(" ");
}
}
}
System.out.print(i + " ");
int tempValue = i - 1;
while(tempValue>0)
{
System.out.print(tempValue);
if(tempValue>1)
{
System.out.print(" ");
}
tempValue--;
}
if(tempValue==0)
{
System.out.print("\n");
}
counter--;
}
}
}

Java Number Pattern Recursion

I am working on a lab for a class where a user inputs a number and it recursively prints out a number pattern. For example,
The base case is if they enter 1, it will print: 1
If they enter 2 it will print: 1 2 1
If 3, it will print: 1 2 1 3 1 2 1
and then for something bigger, if they enter 7, it will print:
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 7
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
I'm a little stuck on what the number pattern is to be able to complete this problem. Does anyone have any ideas?
So you need to write a recursive function. Something of this form:
private String pattern(int num) {
// ...
}
The most important part is finding the right exit condition that should stop the recursion. In this case, that's when num == 1.
From the description, it looks like for a number k,
the output is pattern(k - 1) + k + pattern(k - 1).
I already spoiled too much.
You might need to improve the efficiency of this.
For example, realize that you don't need to run pattern(k - 1) twice,
it's enough to do it once.
I'm a little stuck on what the number pattern is to be able to
complete this problem.
Lets try to analyse the sequence using some function f
f(1) = 1 (Total digits = 1)
f(2) = 1 2 1 ( Total digits = 3)
f(3) = 121 3 121 (Total digits = 7)
f(4) = 1213121 4 1213121 (Total digits = 15)
f(5) = 121312141213121 5 121312141213121 (Total digits = 31)
So as you can observe total digits sequence looks like 1,3,7,15,31,....2^n-1
Now we can express this logic as mentioned below(Note : in order to help you to better understand how the program works i am printing sequence at every level)
public class SequenceGenerator {
public static void main(String[] args) {
generate(7);
}
static void generate(int depth) {
recursiveGenerator(1, null, depth);
}
static void recursiveGenerator(int num, String prev, int limit) {
if (num <= limit) {
if (prev != null) {
System.out.println();
}
if (prev != null) {
System.out.printf("%s %d %s", prev, num, prev);
} else {
prev = "";
System.out.printf("%d", num);
}
if (prev.equals("")) {
prev += num + prev;
} else {
prev += " " + num + " " + prev;
}
recursiveGenerator(++num, prev, limit);
}
}
}
Outputs
1
1 2 1
1 2 1 3 1 2 1
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 7 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1

Palindrome Program using Recursion

This is currently what I have for my Palindrome program for my computer science class. I have it pretty much working, except whenever a word is a palindrome, it is an infinite loop. I know I have to insert a number base case, but I do not how to do that...I'm really having trouble understanding recursion. Help is appreciated.
public class PalindromeTester
{
public static void main(String[] args)
{
Scanner scan = new Scanner (System.in);
String str, another = "y";
int left, right;
while (another.equalsIgnoreCase("y"))
{
System.out.println("Enter a potential palindrome:");
str = scan.next();
left = 0;
right = str.length() - 1;
tester(str, left, right);
System.out.println();
System.out.println("Test another palindrome (y/n)?");
another = scan.next();
}
}
public static void tester (String str, int left, int right)
{
Scanner scan = new Scanner (System.in);
while (str.charAt(left) == str.charAt(right) && left < right)
{
System.out.println(str);
tester( str, left + 1, right -1);
}
if (left < right)
{
System.out.println("That string is NOT a palindrome.");
}
else
{
System.out.println("That string IS a palindrome.");
}
}
}
You are using a while loop. With recursion, this is done implicitly.
You have to split the algorithm in small parts.
[] represents left, {} represents right.
[1] 2 3 4 5 6 7 8 9 0 9 8 7 6 5 4 3 2 {1} -->Level 0
1 [2] 3 4 5 6 7 8 9 0 9 8 7 6 5 4 3 {2} 1 -->Level 1
1 2 [3] 4 5 6 7 8 9 0 9 8 7 6 5 4 {3} 2 1 -->Level 2
1 2 3 [4] 5 6 7 8 9 0 9 8 7 6 5 {4} 3 2 1 -->Level 3
1 2 3 4 [5] 6 7 8 9 0 9 8 7 6 {5} 4 3 2 1 -->Level 4
1 2 3 4 5 [6] 7 8 9 0 9 8 7 {6} 5 4 3 2 1 -->Level 5
1 2 3 4 5 6 [7] 8 9 0 9 8 {7} 6 5 4 3 2 1 -->Level 6
1 2 3 4 5 6 7 [8] 9 0 9 {8} 7 6 5 4 3 2 1 -->Level 7
1 2 3 4 5 6 7 8 [9] 0 {9} 8 7 6 5 4 3 2 1 -->Level 8
1 2 3 4 5 6 7 8 9 {[0]} 9 8 7 6 5 4 3 2 1 -->Level 9
So, tester will continue until:
We've reached the middle of the word.
The word is not a palindrome
Example of case 2:
[1] 2 3 A 5 6 7 8 9 0 9 8 7 6 5 4 3 2 {1}
1 [2] 3 A 5 6 7 8 9 0 9 8 7 6 5 4 3 {2} 1
1 2 [3] A 5 6 7 8 9 0 9 8 7 6 5 4 {3} 2 1
1 2 3 [A] 5 6 7 8 9 0 9 8 7 6 5 {4} 3 2 1 --> !!!
I thought this method would be very helpful for the understanding of how is this recursion working
public static String positions(String word, int l, int r) {
char[] a = word.toCharArray();
String s = "";
// [letter] if left, {} if right, [{}] if both
for (int i = 0; i < a.length; i++) {
if (l == i && r == i) {
s += "{[" + a[i] + "]}";
} else if (l == i) {
s += "[" + a[i] + "]";
} else if (r == i) {
s += "{" + a[i] + "}";
} else {
s += a[i];
}
s+=" ";
}
return s;
}
And finally, the tester method.
public static boolean tester(String str, int left, int right) {
System.out.println(positions(str, left, right) +" tester(str, "+left +", "+right+")");
if (left>=right) // case 1
return true; // that's ok, we've reached the middle
// the middle was not reached yet.
// is the condition satisfied?
if (str.charAt(left) == str.charAt(right)) {
// yes. So, lets do it again, with the parameters changed
return tester(str, left + 1, right - 1);
}
//the condition was not satisfied. Let's get out of here.
else {
return false;
}
}
Some outputs:
Enter a potential palindrome:
1234567890987654321
[1] 2 3 4 5 6 7 8 9 0 9 8 7 6 5 4 3 2 {1} tester(str, 0, 18)
1 [2] 3 4 5 6 7 8 9 0 9 8 7 6 5 4 3 {2} 1 tester(str, 1, 17)
1 2 [3] 4 5 6 7 8 9 0 9 8 7 6 5 4 {3} 2 1 tester(str, 2, 16)
1 2 3 [4] 5 6 7 8 9 0 9 8 7 6 5 {4} 3 2 1 tester(str, 3, 15)
1 2 3 4 [5] 6 7 8 9 0 9 8 7 6 {5} 4 3 2 1 tester(str, 4, 14)
1 2 3 4 5 [6] 7 8 9 0 9 8 7 {6} 5 4 3 2 1 tester(str, 5, 13)
1 2 3 4 5 6 [7] 8 9 0 9 8 {7} 6 5 4 3 2 1 tester(str, 6, 12)
1 2 3 4 5 6 7 [8] 9 0 9 {8} 7 6 5 4 3 2 1 tester(str, 7, 11)
1 2 3 4 5 6 7 8 [9] 0 {9} 8 7 6 5 4 3 2 1 tester(str, 8, 10)
1 2 3 4 5 6 7 8 9 {[0]} 9 8 7 6 5 4 3 2 1 tester(str, 9, 9)
true
Test another palindrome (y/n)?
y
Enter a potential palindrome:
12345A678654321
[1] 2 3 4 5 A 6 7 8 6 5 4 3 2 {1} tester(str, 0, 14)
1 [2] 3 4 5 A 6 7 8 6 5 4 3 {2} 1 tester(str, 1, 13)
1 2 [3] 4 5 A 6 7 8 6 5 4 {3} 2 1 tester(str, 2, 12)
1 2 3 [4] 5 A 6 7 8 6 5 {4} 3 2 1 tester(str, 3, 11)
1 2 3 4 [5] A 6 7 8 6 {5} 4 3 2 1 tester(str, 4, 10)
1 2 3 4 5 [A] 6 7 8 {6} 5 4 3 2 1 tester(str, 5, 9)
false
Test another palindrome (y/n)?
In the main method,
System.out.println(tester(str, left, right));
In order to see the true/false output
Since your are using recursion (in its basic purposes mostly used to eliminate loops), isn't your while loop inside the tester() method supposed to be an if?
public static void tester (String str, int left, int right)
{
Scanner scan = new Scanner (System.in);
if (str.charAt(left) == str.charAt(right) && left < right)
{
System.out.println(str);
tester( str, left + 1, right -1);
}
else if (left < right)
{
System.out.println("That string is NOT a palindrome.");
}
else
{
System.out.println("That string IS a palindrome.");
}
}
I modified your tester() method and replaced your while with an if and moved your second if clause.
public static void tester(String str, int left, int right) {
if (str.charAt(left) == str.charAt(right) && left < right) {
tester(str, left + 1, right - 1);
} else {
if (left < right) {
System.out.println("That string is NOT a palindrome.");
} else {
System.out.println("That string IS a palindrome.");
}
}
}

Categories