Iterating through a character array in Java - improving algorithm - java

I'm trying to iterate through my array to produce all possible combinations of the given char array.
If the length I specify is 4 then I want it to iterate through all combinations of the chars in the array up to a length of 4.
It would look something like this:
char[] charArray = "abcdefghijklmnopqrstuvwxyz".toCharArray();
Output of method I want:
a,
b,
c,
...,
x,
y,
z,
aa,
ab,
ac,
...,
ax,
ay,
az,
ba,
bb,
bc,
...,
bx,
by,
bz,
ca,
cb,
cc,
...
zzzx,
zzzy,
zzzz
Here's some code:
cs = charArray;
cg = new char[4]; // 4 up to 4 characters to guess
int indexOfCharset = 0; // should I be using all these?
int indexOfCurrentGuess = 0;
int positionInString = 0;
public void incrementNew() {
// 1 DIGIT guesses
if (cg.length == 0) {
if (indexOfCharset == cs.length) {
cg = new char[cg.length + 1];
} else {
cg[positionInString] = nextChar();
}
}
// 2 DIGIT guesses
else if (cg.length == 1) {
if (cg[0] == cs.length && cg[1] == cs.length) {
cg = new char[cg.length + 1];
} else {
... Something goes here <-
cg[positionInString] = nextChar();
}
}
System.out.println("cg[0]=" + cg[0]);
}
public char nextChar() {
char nextChar;
if (indexOfCharset < cs.length) {
nextChar = cs[indexOfCharset];
} else {
indexOfCharset = 0;
nextChar = cs[indexOfCharset];
}
indexOfCharset++;
//System.out.println("nextChar = " + nextChar);
return nextChar;
}
The only way I can think of doing it is using lots of IF statements - is there an algorithm or way to do it neater? If not then any suggestions on how to deal with two or more characters?
EDIT:
I want it to work for any unsorted char arrays not just a-z.
All the implementations I've found only work for sorted arrays..

You could try this:
static char[] letters = "abcdefghijklmnopqrstuvwxyz".toCharArray();
static void getChars(char[] lastChars, int pos, int length) {
for (char c : letters) {
char[] newChars = lastChars.clone();
newChars[pos] = c; // if you have "aa" for example and the current length is 4. If c = "a", newChars is now "aaa"
if (pos + 1 < length) { // as your lenths is 4 and you still have only 3 letters, getChars adds the missing ones
getChars(newChars, pos + 1, length);
} else {
System.out.println(newChars);
}
}
}
public static void main(String[] args) {
int maxLength = 4;
for (int length = 1; length <= maxLength; length++) {
for (char c : letters) {
if (length > 1) {
char[] chars = new char[length];
chars[0] = c;
getChars(chars, 1, length);
} else {
System.out.println(c);
}
}
}
}

Related

Created a string in Java, S = "httthhhtth". Split it in a half and change second half 'H' into 'T' and 'T' into 'H'

I managed to split the string but how can I swap h with t and t with h in second half of string ?
public class Tollring3 {
public static void main(String args[])
{
String base = "httthhhtth";
int half = base.length()/2;
// int half = base.length() % 2 == 0 ? base.length()/2 : base.length()/2 + 1;
String first = base.substring(0, half);
String second = base.substring(half);
System.out.println("Actual String :- "+base);
System.out.println(first);
System.out.println(second);
char[] c = second.toCharArray();
// Replace with a "swap" function, if desired:
char temp = c[0];
c[0] = c[1];
c[1] = temp;
String swappedString = new String(c);
System.out.println(swappedString);
}
}
How to swap h with t and t with h in second half of string
This program splits a string into two halves, then swaps the first and second characters of the second half.
public class Tollring3 {
public static void main(String args[])
{
String base = "httthhhtth";
int half = base.length()/2;
// int half = base.length() % 2 == 0 ? base.length()/2 : base.length()/2 + 1;
String first = base.substring(0, half);
String second = base.substring(half);
System.out.println("Actual String :- "+base);
System.out.println(first);
System.out.println(second);
char[] c = second.toCharArray();
// Replace with a "swap" function, if desired:
char temp = c[0];
c[0] = c[1];
c[1] = temp;
String swappedString = new String(c);
System.out.println(swappedString);
}
}
You can define the swap function as follows:
String swap(String str) {
char[] arr = str.toCharArray();
char[] result = new char[arr.length];
for (int i = 0; i < arr.length; i++)
result[i] = arr[i] == 'h' ? 't' : arr[i] == 't' ? 'h' : arr[i];
return new String(result);
}
In the function, we have
split the given string (second half) into a char array, arr.
created another char array, result of the same size.
iterates arr to store each character from arr into result while swapping h and t with each other.
finally returned a new String created out of result.
Full demo:
public class Main {
public static void main(String args[]) {
String base = "httthhhtth";
int half = base.length() / 2;
// int half = base.length() % 2 == 0 ? base.length()/2 : base.length()/2 + 1;
String first = base.substring(0, half);
String second = base.substring(half);
System.out.println("Actual String :- " + base);
System.out.println(first);
System.out.println(second);
String swappedString = swap(second);
System.out.println(swappedString);
}
static String swap(String str) {
char[] arr = str.toCharArray();
char[] result = new char[arr.length];
for (int i = 0; i < arr.length; i++)
result[i] = arr[i] == 'h' ? 't' : arr[i] == 't' ? 'h' : arr[i];
return new String(result);
}
}
Output:
Actual String :- httthhhtth
httth
hhtth
tthht
To do the replacement you need to iterate on the chars and use if to test what char it is
String base = "httthhhtth";
System.out.println(base);
char[] c = base.toCharArray();
for (int i = c.length / 2; i < c.length; ++i) {
if (c[i] == 'h') {
c[i] = 't';
} else if (c[i] == 't') {
c[i] = 'h';
}
}
String swappedString = new String(c);
System.out.println(swappedString);
httthhhtth
httthtthht

JAVA // How do i make it case-insensitive?

import java.util.Random;
public class MergeSortEx {
public static void mergeSort(char[] array) {
sortArray(array, 0, array.length);
}
private static void sortArray(char[] array, int start, int end) {
if (end-start <2)
return;
int mid = (start + end) / 2;
sortArray(array, 0, mid);
sortArray(array, mid, end);
mergeArray(array, start, mid, end);
}
private static void mergeArray(char[] array, int start, int mid, int end) {
char[] temp = new char[end - start];
int t = 0, s = start, m = mid;
while (s < mid && m < end) {
if (array[s] < array[m])
temp[t++] = array[s++];
else
temp[t++] = array[m++];
}
while (s < mid) {
temp[t++] = array[s++];
}
while (m < end) {
temp[t++] = array[m++];
}
for(int i=start;i<end;i++) {
array[i]=temp[i-start];
}
}
public static void main(String[] args) {
char[] randomString = new char[20];
Random rnd = new Random();
for (int i = 0; i < 20; i++) {
if (i < 10)
randomString[i] = (char) (rnd.nextInt(6) + 'A');
else
randomString[i] = (char) (rnd.nextInt(6) + 'a');
}
System.out.println(randomString.length);
for (int i = 0; i < 20; i++)
System.out.print(randomString[i] + " ");
mergeSort(randomString);
System.out.println();
for (int i = 0; i < 20; i++)
System.out.print(randomString[i] + " ");
}
}
I used the translator.
It's a university algorithm assignment, Merge sort implemented successfully.
Now, capital letters come out first, and lowercase letters come out.
Can make the code case-insensitive?
I want the results to be like this.
ex) a A A B b C c c D d ...
plz help.
Instead of comparing using if (array[s] < array[m]) directly, convert the characters to uppercase before comparing, similar to what String.compareToIgnoreCase(...) does:
if (Character.toUpperCase(array[s]) < Character.toUpperCase(array[m]))
That is for sorting individual characters. For sorting String values, there are two ways to make a case-insensitive sort:
Use the predefined String.CASE_INSENSITIVE_ORDER Comparator.
stringList.sort(String.CASE_INSENSITIVE_ORDER);
Use a Collator:
Collator collator = Collator.getInstance(Locale.US);
stringList.sort(collator);
That will sort localized alphabets correctly, e.g. if you specified Locale.GERMANY, it would sort upper- and lower-case letters together, but will e.g. also sort Ð between D and E, and sort ß same as S.
Just replace:
while (s < mid && m < end) {
if (arr[s] < arr[m])
temp[t++] = arr[s++];
else
temp[t++] = arr[m++];
}
with
while (s < mid && m < end) {
if (Character.toLowerCase(arr[s]) < Character.toLowerCase(arr[m]))
temp[t++] = arr[s++];
else
temp[t++] = arr[m++];
}
If you want small letters come first like aAbbbBBBcCCCD then try following.
Instead of:
array[s] < array[m]
Use:
private static boolean charCompare(char a, char b) {
char ua = Character.toUpperCase(a);
char ub = Character.toUpperCase(b);
if(ua == ub) {
return a > b;
} else {
return ua < ub;
}
}
Output:
20
F E E A D A B C A E a e c f d f c a f e
a a A A A B c c C d D e e E E E f f f F

Problem encryption exercise with ASCII table

I have a problem with this exercise.
In this exercise I enter a word and a number. I have to use the ASCII table to encrypt the word.
If I enter the letter "a" and the number 3, the letter becomes "d".
If I enter the letter "z" and the number 2, the letter should become "b", but a symbol comes out.
Another problem is if I use an uppercase letter. If I enter the uppercase letter "Z" I'll still get a symbol.
Another problem is if I use the letters "aB" and the number -2 should come out "yZ", but symbols come out.
This is the exercise:
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String s, n="";
int N;
System.out.println("Insert a word");
s=in.next();
System.out.println("Insert a number");
N=in.nextInt();
n=uno(s, N);
System.out.println("That's the encrypted word: " + n);
}
public static String uno (String s, int N) {
String f, n="";
int c;
int length = s.length();
for (int i=0; i<length; i++) {
c = s.charAt(i);
c=c+N;
f = Character.toString((char)c);
n=n+f;
}
return n;
}
ASCII for z is 122. You add 2 to that. The ASCII for 124 is | symbol.
You need to check if your addition is going out of range (i.e. above 122).
Note: this won't work is N is greater than 26. Check the solution just below that implements modulo to handle that.
public static String uno (String s, int N) {
String f, n = "";
int c;
int length = s.length();
for (int i = 0; i < length; i++) {
c = s.charAt(i);
c = c + N;
if (c >= 122) {
c -= 26;
}
f = Character.toString((char) c);
n = n + f;
}
return n;
}
Side note: Never concatenate a string in a loop using +. It is very inefficient. Using StringBuilder.
Handle case sensitive letters concisely:
public static String uno (String s, int N) {
StringBuilder n = new StringBuilder();
int bound = s.length();
IntStream.range(0, bound).forEach(i -> {
char c = s.charAt(i);
n.append(Character.isUpperCase(c) ?
(char) ((c + N - 'A') % 26 + 'A') :
(char) ((c + N - 'a') % 26 + 'a'));
});
return n.toString();
}
Handling negative numbers:
public static String uno (String s, int N) {
StringBuilder n = new StringBuilder();
int bound = s.length();
IntStream.range(0, bound).forEach(i -> {
char c = s.charAt(i);
if (N > 0) {
n.append(Character.isUpperCase(c) ?
(char) ((c + N - 'A') % 26 + 'A') :
(char) ((c + N - 'a') % 26 + 'a'));
} else {
n.append((char) (c + N % 26 + 26));
}
});
return n.toString();
}
Check this comment for a good point on your naming conventions.

Sorting a string with Capital small and numbers

Sort a string with small capital and numbers in Java
aAbcB1C23 .
Answer ABCabc123.
I tried sorting the array both ascending as well as decending but did not work as in both the ways ABC is coming in the middle. Any ideas ?
I'd like to solve with O(1) auxillary space and may be O(n log n) time ..
public class SortTheGivenStringAlphabetically {
public static void performAction() {
String input = "aAbcB1C23";
char[] inputCharArray = input.toCharArray();
sort(inputCharArray, 0, (inputCharArray.length) - 1);
for (int i = 0; i < inputCharArray.length; i++) {
System.out.println(inputCharArray[i]);
}
}
public static void sort(char[] array, int low, int high) {
if (low < high) {
int pi = partition(array, low, high);
sort(array, low, pi - 1);
sort(array, pi + 1, high);
}
}
private static int partition(char[] array, int low, int high) {
int pivot = array[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (array[j] <= pivot) {
i++;
char temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
char temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
public static void main(String[] args) {
performAction();
}
}
Create 3 ArrayLists.
Separate all characters from the input and add them to the specific ArrayList.
Then sort them using Collections.sort().
Finally combine all the characters in the order you want.
String input = "aAbcB1C23";
ArrayList<Character> capital = new ArrayList(),
simple = new ArrayList(),
numbers = new ArrayList();
for (Character c : input.toCharArray()) {
if (Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
capital.add(c);
} else {
simple.add(c);
}
} else {
numbers.add(c);
}
}
Collections.sort(simple);
Collections.sort(capital);
Collections.sort(numbers);
StringBuilder output = new StringBuilder();
for (Character c : capital) {
output.append(c);
}
for (Character c : simple) {
output.append(c);
}
for (Character c : numbers) {
output.append(c);
}
System.out.println(output.toString());
Output:
ABCabc123
The meanness is that the natural order is '1' (49) < 'A' (65) < 'a' (97).
String input = "aAbcB1C23"; // Sorted: ABCabc123
char[] array = input.toCharArray();
sort(array, 0, (array.length) - 1);
So either you could reorder the wrongly sorted result:
output = output.replaceFirst("^([0-9]*)([A-z]*)$", "$2$1");
or map every concerned char to a correct value: easiest with a function:
int value(char ch) {
if ('A' <= ch && ch <= 'Z') {
return 100 + (ch - 'A');
} else if ('a' <= ch && ch <= 'z') {
return 200 + (ch - 'a');
} else if ('0' <= ch && ch <= '9') {
return 300 + (ch - '0');
} else {
return 400 + (int) ch;
}
}
Now compare value(array[i]).
First loop iterate no of times the no of character present in String.And last two loops run for constant time (78 times).So time complexity wise it could be effecient.
public static String SortSstring(String input) {
int []intArr=new int[78];
for(int i=0;i<input.length();i++)
intArr[input.charAt(i)-48] ++;
String OutputString="";
for(int i=17;i<78;i++){
OutputString+=String.valueOf(new char[intArr[i]]).replace('\0', (char)(i+48));
}
for(int i=0;i<10;i++){
OutputString+=String.valueOf(new char[intArr[i]]).replace('\0', (char)(i+48));
}
return OutputString;
}
}
One option is to use integer value of a character when doing comparison. To make numbers appear at the end we can add some fixed value to it (e.g. 100).
public static void main(String[] args) {
String input = "aAbcB1C23";
char[] charArray = input.toCharArray();
Character[] charObjectArray = ArrayUtils.toObject(charArray);
Arrays.sort(charObjectArray, new Comparator<Character>() {
#Override
public int compare(Character o1, Character o2) {
Integer i1 = convert(Integer.valueOf(o1));
Integer i2 = convert(Integer.valueOf(o2));
return i1.compareTo(i2);
}
private Integer convert(Integer original) {
if (original < 58) {
return original + 100;
}
return original;
}
});
System.out.println(new String(ArrayUtils.toPrimitive(charObjectArray)));
}

Vignere Cipher encryption/decryption using arrays

I need to first encrypt and then decrypt a message using the Vigenere cypher. This is how it should work
example message: "c a t s _ d o g s"
keyword "rats": r a t s r a t s r
order of the letter in the message (start at a=0):2 0 19 18 () 3 14 6 18
order of the letter in the keyword: 17 0 19 18 17 0 19 18 17
sum of the two orders: 19 0 38 36 17 3 39 24 35
new letter for the message* t a m k d h y j
encrypted message = "tamk uoyk"
Note: if the sum > 26 then we subtract 26 from the sum to get a cyclical alphabet. Example:
z + b = 25 + 1 = 26; 26 - 26 = 0 --> a
I have written the methods to obtain the numerical value of the keyword, and also two methods that "add" or "subtract" individual letters and two methods that perform the caesar encoding/decoding (simply shifting the entire message by an int to the right in the alphabet, or to the left to decrypt).
The piece that I really need help for is to how to create a for loop that's going to repeat the keyword the appropriate amount of times (to have the same length as the message) and proceed to the obtainKeys method to get the numerical values of the repeated key.
Here is my entire program; the part I am struggling with is at the end (Q2f)
import java.util.Arrays;
public class Cypher {
public static void main(String[] args) {
System.out.println(charRightShift('z', 3));
System.out.println(charLeftShift('z', 3));
String test = caesarEncode("cats and dogs", 5);
System.out.println(test);
System.out.println(caesarDecode(test, 5));
obtainKeys("abcxyz");
System.out.println(vigenereEncode("elephants", "rats"));
}
//Q2a-b
//Generalized method for char shifts
public static char charShift(char c, int n) {
//value of n should be between 0 and 25
if (Math.abs(n) < 0 || 25 < Math.abs(n)) {
//returning the ascii value of '0' which
//is nul & adding error message
int zero = 0;
c = (char) zero;
throw new IllegalArgumentException("n has to be 0<=|n|<=25");
}
//character c should be a lower case latin letter
//if not, we simply return c, the original character,
//skipping this else if
else if (c >= 'a' && c <= 'z') {
c = (char) (c + n);
if (c > 'z') {
c = (char) (c - 26);
} else if (c < 'a') {
c = (char) (c + 26);
}
}
return c;
}
//method that shifts the value of the character to the right
public static char charRightShift(char c, int n) {
c = charShift(c, n);
return c;
}
//method that shifts the value of the character to the left
public static char charLeftShift(char c, int n) {
n = -n;
c = charShift(c, n);
return c;
}
//Q2c
//method that shifts the message to the right by int 'key' characters
public static String caesarEncode(String message, int key) {
//transform string into char array
char[] messageEncrypt = message.toCharArray();
//for each char, we shift it by 'key' ints,
//using charRightShift method
for (int i = 0; i < messageEncrypt.length; i++) {
char c = messageEncrypt[i];
c = charRightShift(c, key);
messageEncrypt[i] = c;
}
return new String(messageEncrypt);
}
//Q2d
//method that shifts the message to the left by int 'key' characters
public static String caesarDecode(String message, int key) {
//transform string into char array
char[] messageDecrypt = message.toCharArray();
//for each char, we shift it by 'key' ints using charLeftShift
for (int i = 0; i < messageDecrypt.length; i++) {
char c = messageDecrypt[i];
c = charLeftShift(c, key);
messageDecrypt[i] = c;
}
return new String(messageDecrypt);
}
//Q2e
//method to obtain the int array storing the numerical value of the String
public static int[] obtainKeys(String s) {
//creating int array where we're going to
//store the numerical value of the String
int[] keys = new int[s.length()];
int j;
//for each ascii value of the char in string s, we substract 97 to
//get the lower case english alphabet character corresponding to it
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
j = c - 97;
//now store every int in the int array
keys[i] = j;
}
String keysString = Arrays.toString(keys);
return keys;
}
//Q2f
public static String vigenereEncode(String message, String keyword) {
//for loop check if there are any 'illegal' characters in the keyword
char[] kword = keyword.toCharArray();
for (int i = 0; i < kword.length; i++) {
char c = kword[i];
if (c < 'a' || c > 'z') {
throw new IllegalArgumentException(
"The keyword must only contain characters " +
"from the lower case English alphabet.");
}
}
int[] numMessage = obtainKeys(message);
int[] numKeyword = obtainKeys(keyword);
for (int i = 0; i < message.length(); i++) {
for (int j = 0; j < keyword.length(); i++) {
//NOT SURE IF I NEED A NESTED LOOP HERE
//WHAT TO DO HERE?
}
}
return messageVigenere;
}
}
You can do this by using the mod operation %.
char[] messageArray = message.toCharArray();
char[] encryptedMessage = new char[messageArray.length];
int[] numKeyword = obtainKeys(keyword);
int keywordLength = numKeyword.length;
for(int i=0; i<message.length(); i++){
int shiftAmount = numKeyword[i % keywordLength];
char c = messageArray[i];
c = charRightShift(c,shiftAmount);
encryptedMessage[i] = c;
}
Instead of repeating the keyword til it is the length of the message, you can find which letter is needed using modulus logic. For any location n in the message, the keyword letter is keyword[n % keyword.length()].

Categories