I'm working on key columnar transposition cipher,
for(int i = 0; i < column; i++){
position = keyWord.indexOf(sorted_key[i]); // Here's the problem
for(int j = 0; j < row; j++){
matrix[j][position] = cipher_array[count];
count++; }}
Keyword is:
analyst
sorted_key is:
{a, a, l, n, s, t, y}
When I tried to print the variable position:
0 0 3 1 5 6 4
But I'm supposed to get this:
0 2 3 1 5 6 4
The problem occurs when I have a duplicated letter in the key. 'a' in this example, it always sees the first index of it's occurrence even if there's a second or third occurrence of it. How could this be fixed?
You can maintain a Map that holds the last index for each character:
Map<Character,Integer> indices = new HashMap<>();
for(int i = 0; i < column; i++) {
// get the previous position of sorted_key[i] (or -1 is there is no previous position)
int last = indices.computeIfAbsent(sorted_key[i],c->-1);
// search for the next position of sorted_key[i]
position = keyWord.indexOf(sorted_key[i],last+1);
// store the next position in the map
indices.put(sorted_key[i],position);
for(int j = 0; j < row; j++) {
matrix[j][position] = cipher_array[count];
count++;
}
}
Related
I'm trying to print an element of a 2D array by designating it's location with an index. Say, I want to print location 3 which would be String[1][0] for my array.
String[][] fruit = new String[2][2];
fruit[0][0] = "apple"; //position 1
fruit[0][1] = "banana"; //position 2
fruit[1][0] = "pear"; //position 3
fruit[1][1] = "melon"; //position 4
I would like to call fruit[1][0] position 3 so when I ask to print "position 3" it gives me "pear".
What you're looking for is obviously the literal position of a cell since arrays start from an index value of 0. You also need to keep in mind that a 2D Array can possibly have different number of columns for any given row. The first and second rows for example may have 4 columns, the fifth row might have 6 columns, and the sixth, seventh row may have 4 columns again. Unless you know for sure that all columns within the Array are indeed fixed to a specific length (a "square" 2D Array), I can't see an advantage to this scheme.
Never the less, this can be easily done with two for loops (one nested within the other), for example:
String[][] array = {
{"cell 1", "cell 2"}, // Row 1 (index 0)
{"cell 3", "cell 4", "cell 5"}, // Row 2 (index 1)
{"cell 6", "cell 7"}}; // Row 3 (index 2)
int yourDesiredCell = 5;
int cellCount = 0;
boolean found = false;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
cellCount++;
if (cellCount == yourDesiredCell) {
System.out.println(array[i][j]);
found = true;
break;
//return array[i][j];
}
}
if (found) {
break;
}
}
You could also place this into a class method, for example:
public static String getCellData(String[][] array, int yourDesiredCell) {
int cellCount = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
cellCount++;
if (cellCount == yourDesiredCell) {
return array[i][j];
}
}
}
return null;
}
Another method that could be handy is retrieving the total number of actual cells contained within the 2D Array (if you don't already know):
public static int getTotalCellCount(String[][] array) {
int cellCount = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
cellCount++;
}
}
return cellCount;
}
What I got from your question was that there is a multi-dimensional array A of size say nxm where n is number of rows and'mis number of columns. You want to get let say 1st element which will beA[0][0], but you don't know how to convert 1` into indices for the array.
Lets do this for a 2d array A of size nxm, then you can extend it to 3d etc too. Remember that each A[i] is an array of'melements, hence the position of row where the element isx/m, i=x/m. No need to make it 0-indexed because the integer division of java does that for you. If i>=n`, then we should say element is not present.
Now you have to decide the position of the element in m elements. Hence j or position of the column is x%m. This will give you index b/w 0 and m-1 which is correct range of j, but for an element in the first place it should give 0, but it's giving 1. Hence it js not 0-indexed. So j= x%m -1 but for (m-1)th element its giving
-1 as x would be divisible by m or x%m=0. So use ternary operator here, j = x%m-1 < 0 ? m-1 : x%m-1.
i = x/m ;
if(i<n){
j = x%m -1 < 0 ? m-1 : x%m -1 ;
}else{
System.out.println("Element " +m+" does not exist") ;
}
I would like to suggest another approach with a time complexity O(n).
public String getByPosition(int pos,String[][] mulArr){
int row,col;
int temp = pos;
while(temp % mulArr.length != 0)temp++;
row = (temp / mulArr.length) - 1;
col = ((pos % mulArr[0].length) - 1 < 0) ? mulArr[0].length - 1 : (pos % mulArr[0].length) - 1;
return mulArr[row][col];
}
The first 4 values are set properly in the new array. It has to do with something with my variable 'count' which is not being set properly. The goal of the program is to simply grab the even numbers, and put them in a new array.
I have added 4 to count as a test, and that seems to work perfectly but I dont think that is the issue here.
int[] list = {8,5,4,11,12,2,1,3,10,6,7};
int count = 0;
int gr = 0;
for(int n=0; n<list.length; n++)
{
if(list[n] % 2 == 0)
{
count++;
}
}
int[] evn = new int[count];
for(int k = 0; k<=count; k++)
{
if(list[k] % 2 == 0)
evn[gr++] = list[k];
}
return evn;
Currently, the array prints "8,4,12,2,0,0" when it should print "8,4,12,2,10,6"
This happens because count is always less than the size of the array(list.length), so in the second for-loop you are never iterating till the end of the array.
Change your second for-loop to iterate till the end of the array as shown below :
for(int k = 0; k < list.length; k++)
You're only traversing part of list, as stated in the for condition:
for(int k = 0; k<=count; k++)
^--here--^
This is because count has a lower value than the length of the original array. Change this condition to traverse the whole array:
for(int k = 0; k<list.length; k++)
To traverse the whole list change the following:
for(int k = 0; k<=count; k++)
To
for(int k = 0; k<list.length; k++)
Given a problem that determines the output of the word, length of each word, and the number of times the word repeats, I have the following code capable to determine the word and length of each word below:
String sentence;
String charSentence;
String[] wordOutput;
private void analyzeWords(String s) {
String[] words = sentence.split(" ");
wordOutput = new String[words.length];
int[] repeats = new int[words.length];
// Increment a single repeat
for (int i = 0; i < words.length; i++) {
repeats[i] = 1;
// Increment when repeated.
for (int j = i + 1; j < words.length - 1; j++) {
if (words[i].equalsIgnoreCase(words[j])) {
repeats[i]++;
}
}
wordOutput[i] = words[i] + "\t" + words[i].length() + "\t" + repeats[i];
}
When I run the program, I get the following output:
Equal 5 2
Equal 5 1 <- This is a duplicate word and should not be here when it repeats.
Does anyone know where my problem is? Is it something relating that deals with my repeats array?
The first problem is that in the inner for loop you are looping from i+1 to length-1. You need to loop till length. Second you will need to determine if there are any occurrences of the word in the String, and if so use a continue statement. You can do:
outer:
for (int i = 0; i < words.length; i++) {
repeats[i] = 1;
for(int index = i-1; index >= 0; index--) {
if(words[i].equals(words[index])) {
continue outer;
}
}
...
}
However the problem with this is that there will be null values at the end of the list, as you specify an Array with the same length as the number of words. To solve this you can do:
wordOutput = Arrays.stream(wordOutput).filter(e-> e!= null).toArray(String[]::new);
Which will filter out the null values
Output:
(With the input String: "This is a String is a with a lot lot of this repeats repeats")
This 4 2
is 2 2
a 1 3
String 6 1
with 4 1
lot 3 2
of 2 1
this 4 1
repeats 7 2
Instead of incrementing count at all index store the count only in last occurence of word, in other case, have the count value of 0. at the end traverse the count array, if its greater than zero, print the value and its count
private void analyzeWords(String s) {
String[] words = sentence.split(" ");
wordOutput = new String[words.length];
int[] repeats = new int[words.length];
for (int i = 0; i < words.length; i++) {
int count =1;
int index = i;
for (int j = i + 1; j < words.length - 1; j++) {
if (words[i].equalsIgnoreCase(words[j])) {
count++;
index = j;
}
}
if(repeats[index]==0){
repeats[index]=count; // update repeat array only for last occurence of word
wordOutput[i] = words[i] + "\t" + words[i].length() + "\t" + repeats[index];
}
}
First, as GBlodgett mention you should check all left words for repeats, your current solution skips last word. Update second loop termination condition to j < words.length.
Second, if you want to print duplicates only once you need a condition in your solution. One of the example:
boolean[] duplicates = new boolean[words.length];
// Increment a single repeat
for (int i = 0; i < words.length; i++) {
repeats[i] = 1;
// Check for duplicates,
// If the word was not marked as duplicate
if (!duplicates[i]) {
// Increment when repeated.
for (int j = i + 1; j < words.length; j++) {
if (words[i].equalsIgnoreCase(words[j])) {
repeats[i]++;
duplicates[j] = true;
}
}
wordOutput[i] = words[i] + "\t" + words[i].length() + "\t" + repeats[i];
}
}
There is a Java 8+ solution, for example:
Map<String, Long> m = Arrays.stream(s.split(" ")).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Map will have pairs of word and it occurrences.
I have a string containing the following:
String text = "abcdefghijkl"
I want to put it in a 2d array so there will be 4 rows of 3
this is currently what I have, its not working correctly though:
char boxChar[][] = new char[4][3];
int j,i;
for (i = 0; i<4; i++)
{
for (j=0; j<3; j++)
{
boxChar[i][j] = text.charAt((i+1)*(j));
}
}
return boxChar[row][col];
It looks like you got the indexes mixed up. I added some print statements to your original code with a modification to get the right char in your charAt instruction.
String text = "abcdefghijkl";
char boxChar[][] = new char[4][3];
int j,i;
for (i = 0; i<4; i++)
{
for (j=0; j<3; j++)
{
boxChar[i][j] = text.charAt(i*3+j);
System.out.print(boxChar[i][j]);
}
System.out.println();
}
Sometimes it can be helpful to jot it down on a piece of paper if it's not lining up how you expected.
With your input string, the positions on a 1d array are
a b c d e f g h i j k l
0 1 2 3 4 5 6 7 8 9 10 11
As you loop through to get the box array (matrix), your outer loop indicates that you want four rows and three columns, in other words
a b c
d e f
g h i
j k l
so for the first element, a, its position is (0,0), b is at (0,1) and so on. Your charAt(position) has to map the 2d positions to their corresponding 1d positions.
Just the wrong indexing, otherwise you're good:
String text = "abcdefghijkl";
int rows = 4;
int cols = 3;
char boxChar[][] = new char[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
boxChar[i][j] = text.charAt((i * cols) + j);
}
}
//return boxChar[row][col];
System.out.println(boxChar[0]);
System.out.println(boxChar[1]);
System.out.println(boxChar[2]);
System.out.println(boxChar[3]);
I'm working on a Java program that checks if a sudoku puzzle is solved or not. I have finished the horizontal and vertical number check part. But when trying to check squares, I can't do anything. Here is how my check system works.
This is what I want to make. Hope someone helps because I'm on a hard situation with square check.
int[][] SudokuBoard = new int[9][9];
// I didn't wrote the sudoku board completely hope you understood how sudoku table looks like.
public static boolean checkSquares(int[][] SquareBoard) {
int retr = false;
int loop = 0;
int[] extraboard = new int[9];
int[] truelist ={1,2,3,4,5,6,7,8,9};
for(int i = 1; i <=9 ; I++) {
//here , extraboard will have the numbers in " i " numbered sudoku square.( i is like first //,second)
Arrays.sort(extraboard);
for(int j = 0; j < 9; j++) {
if(extraboard[j] == truelist[j])
loop += 1;
}
extraboard = new int[9];
}
if(loop == 81)
retr == true;
return retr;
}
You could do
int count = 0;
for(int k = 0; k < 9; k++) {
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
extraboard[count++] = SquareBoard[i+3*k/3][j+k%3*3];
}
}
Arrays.sort(extraboard);
for(int j = 0; j < 9; j++) {
if(extraboard[j] == truelist[j])
loop += 1;
}
extraboard = new int[9];
count = 0;
}
The actual formula to calculate the location in the box is quite simple. As the board is split into rows and column, getting the location of the row and column needs to get offset based on the location of the box in the full area.
i here counts the index within the box of the row. As each row of boxes has a length of 3 in a 9x9 sudoku we need to increase the row number by 3 each time we get 3 boxes in. To figure out and only add 3 we can use some integer division.
For example:
i+i.length*k/i.length
This is obviously an syntax error as i doesn't have length but can consider it as the limit of i in the loop (in this case 3).
This would then get the current row in the box (the first i) and add that to the offset of boxes in the sudoki. That is for every 3 boxes k/i.length becomes 1 more, and we then multiply that with 3 to get the offset of 3.
In the column part we have a bit of an bigger issue as we need to offset it for every 3 we move left in the array and reset it when we get back to boxes on the far left.
So the forumla would become
j + (k%i.length)*j.length
This would give us the column in the box we are in, then we offset by the box location with k%i.length. The reason we use the i.length and not the j.length is that we need to calculate the offset by rows and then offset it by the length of the box column wise.
With this you can then apply to this to any size board. 2x2, 2x3, 3x2, 3x3 or bigger even.
public static boolean checkSquares(int[][] SquareBoard) {
int i=0, extraboard=0;
for (;i<9;i++,extraboard=0) {
for (int j=0;j<9;j++)
extraboard+=1<<(SquareBoard[i/3*3+j/3][i%3*3+j%3]-1);
if (extraboard!=(1<<9)-1) // 511, binary(511) = 111111111
break;
}
return i==9;
}
This is a solution i came up with. it uses 4 nested loops but the time complexity is still O(n^2). Basically i check the first 3 boxes on top, then the 3 boxes in the middle, then the last 3 boxes.
for (int l = 0; l < 9; l+= 3){
for (int i = 0; i < 9; i += 3){
HashSet<Character> set = new HashSet<>();
for (int j = l; j < l+3; j++){
for (int k = i; k < i+3; k++){
if (!set.contains(board[j][k])){
if (board[j][k] != '.')
set.add(board[j][k]);
}
else
return false;
}
}
}
}
return true;
and note that the sudoku might not be complete, and the missing numbers are replaced by ' . '