Failing one test for Ceaser Cypher Encrpytor online judge - java

Hello friends I am using online judge for practice
I try this question for a long time to try pass all tests but it is failing 1 test
Here is the code
public static String caesarCypherEncryptor(String str, int key) {
char[] newLetters = new char[str.length()];
for (int i = 0; i < str.length(); i++) {
int newLetterCode = str.charAt(i) + key;
if (newLetterCode <= 122) {
newLetters[i] = (char)(newLetterCode);
} else {
newLetters[i] = (char)(96 + newLetterCode % 122);
}
}
return new String(newLetters);
}
Please point me in direction of want is reason for fail test

Think about what will happen when the passed in key is large enough such that newLetterCode % 122 is greater than 26.
newLetters[i] will not be a lowercase ASCII letter, right? Because the ASCII code for z is 122.
An easy fix for this is to simply change the line:
int newLetterCode = str.charAt(i) + key;
to
int newLetterCode = str.charAt(i) + key % 26;
This will prevent newLetterCode from ever being greater than 147. Which means newLetters[i] will always be a letter within a-z which your code currently is not enforcing.

Related

How can I loop through all the characters that are 0 in a given string?

I'm trying to remove trailing zeroes from an integer and here is my code so far.
import java.math.BigInteger;
public class newuhu {
public static int numTrailingZeros(int s) {
BigInteger J = BigInteger.valueOf(s);
String sb = J.toString();
String Y = "";
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '0') {
sb.replaceAll("0"," ");
}
return Integer.parseInt(Y);
}
Note: I turned my int into a Biginteger because I've been warned that some inputs may look like 20!, which is 2.432902e+18
However, my IntelliJ debugging tool tells me that variable sb isn't in the loop. So, I'm trying to understand what must be done to make sure sb is in the loop.
Please understand that I'm a beginner in Java so, I'm trying to learn something new.
replaceAll replaces all occurrences of string with character that you want (ie space) so you don't need loop at all, also you're concerned about overflow so you should actually use BigInteger as a parameter, not int (int wont fit anything close to 20!) but there's another issue with your code, you said you want to replace trailing zeros but right now you will replace every 0 with blank character, you should try to use something like https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html
public class newuhu {
public static int numTrailingZeros(BigInteger s) {
String sb = s.toString();
return Integer.parseInt(sb.replaceAll("0", "")); // consider returning something else if you're working with BigInteger
}
Keep in mind that when doing BigInteger.valueOf(int) does not have an effect as a number to big for int will never be stored in an int. Also 20! is fine for int.
public static String trimTrailingZeros(String source) {
for (int i = source.length() - 1; i > 0; ++i) {
char c = source.charAt(i);
if (c != '0') {
return source.substring(0, i + 1);
}
}
return ""; // or return "0";
}
Or if you prever BigInteger.
public static BigInteger trimTrailingZeros(BigInteger num) {
while (num.remainder(BigInteger.TEN).signum() == 0) {
num = num.divide(BigInteger.TEN);
}
return num;
}
This should be fast as you only create one string (via substring).
(First: variables and fields should start with a small letter - when no constants.)
It should be
sb = sb.replaceAll(...)
as sb is not changed by replaceAll, only the replaced value is returned. The class String gives immutable values, that always remain the same, so you can assign a variable to a variable and changing values of either variable will never influence the other - no further sharing.
Then it should be:
sb = sb.replaceFirst("0$", "");
replaceAll would replace every 0, like "23043500" to "23435".
replaceFirst replaces the _regular expression: char '0' at the end $.
Overflow on the input number is not possible, as you are already passing an int.
public static int numTrailingZeros(int n) {
while (n != 0 && n % 10 == 0) {
n /= 10;
}
return n;
}
public static int numTrailingZeros(String n) {
n = n.replaceAll("0+", "");
if (n.isEmpty() || n.equals("-")) { // "-0" for pessimists?
n = "0";
}
return Integer.parseInt(n);
}
% is the modulo operator, the remainder of an integer division 147 % 10 == 7.
The name is misleading, or you are calculating something different.
public static int numTrailingZeros(int n) {
int trailingZeros = 0;
while (n != 0 && n % 10 == 0) {
n /= 10;
++trailingZeros ;
}
return trailingZeros ;
}
The problem here is that sb.replaceAll("0","") won't do anything. You're throwing away the return value that contains your replaced string. See here.
What you probably want is something like this:
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '0') {
sb = sb.replaceAll("0"," ");
I'm not sure you need a while loop, though. ReplaceAll will... replace all of the zeros with spaces.

Caesar Cipher with Ascii Characters

I'm trying to encrypt a String using ascii characters with a key position integer. I've got two methods, one for encrypting, one for decrypting.
The problem is that when the character value is above 126, I try to mod 126 it and then add 32 back into it but I get numbers far out of these limits.
public static String encrypt(String s, int k) {
char[] arr = s.toCharArray();
int ascii;
for(int i = 0; i < arr.length; i++) {
ascii = (int) arr[i];
ascii = ascii + k;
// System.out.println(ascii);
if (ascii > 126) {
ascii = 32 + (126 % ascii);
// System.out.print("Changed: " + ascii);
}
arr[i] = (char) ascii;
}
return String.valueOf(arr);
}
The two commented out lines were for testing, and the changed values are crazy high, like instead of going from 127 % 126 = 1 + 32 for a total of 33 (intended value), I get 15870.
First, as mypetlion mentioned, the modulo operation a % b equals the remainder when a is divided by b. E.g. 11 % 4 = 3, 8 % 15 = 8. To be precise, it is the value k that satisfies b * n + k = a, b * (n + 1) > a, k < b where n is an integer. There are more appropriate descriptions using discrete maths and I'm ignoring negative arguments but they are not important. So in your case you should be doing ascii % 128.
As of why the modulo should be 128 and not 126, 7 bit ascii code goes from 0-127, 128 values in total. Also I'm a bit confused as to what the +32 is for, since you already did +k.
Also you can omit your if block completely because c % 128 = c for any c in range [0, 128).
So I would write the following code:
public static String encrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
arr[i] = (char) ((arr[i] + k) % 128);
}
return String.valueOf(arr);
}
public static String decrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
arr[i] = (char) ((arr[i] + 128 - k % 128) % 128);
// + 128 - k % 128 because I don't want do deal with negative numbers.
}
return String.valueOf(arr);
}
I am confident my code will work (for all positive values of k), but I cannot explain why your code produced some crazy high ascii values. When I ran your code on my IDE it didn't do that nor could I see why it would from your code.
Finally, this cipher method will encrypt and decrypt alright, but note that ascii does contain lots of control characters that are not print-friendly. So if you want to limit your cipher vocabulary to only letters and punctuations, you would need to do some character mapping to limit the characters you want to encrypt and encrypt to. This will be much more complicated, not to mention that you would have to consider problems like CR+LF in Windows v. LF in Unix. The following is a simple example that only encrypts and decrypts letters.
public static int asciiToCustom(char ascii) {
// Maps 65-90 & 97-122 to 0-51.
int customCode;
if(ascii >= 65 && ascii <= 90){
customCode = ascii - 65;
}
else if(ascii >= 97 && ascii <= 122){
customCode = ascii - 71;
}
else{
throw new RuntimeException("not a letter!");
}
return customCode;
}
public static char customToAscii(int custom) {
// Maps 0-51 to 65-90 & 97-122.
int ascii;
if(custom >= 0 && custom <= 25){
ascii = custom + 65;
}
else if(custom >= 26 && custom <= 51){
ascii = custom + 71;
}
else{
throw new RuntimeException("not a valid custom code!");
}
return (char) ascii;
}
public static String encrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
if(Character.isLetter(arr[i])){
arr[i] = customToAscii((asciiToCustom(arr[i]) + k) % 52);
}
}
return String.valueOf(arr);
}
public static String decrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
if(Character.isLetter(arr[i])){
arr[i] = customToAscii((asciiToCustom(arr[i]) + 52 - k % 52) % 52);
// + 52 - k % 52 because I don't want do deal with negative numbers.
}
}
return String.valueOf(arr);
}
Your modulo statement is written backwards for a start. Try:
ascii = 32 + (ascii % 126);

java alphabet loop reset to beginning

I want to create a loop where when you add a number, it gives you the equivalent character in that position in the alphabet. For example, a = 0, b = 1 etc..
I've already created that and it works, but the problem I have is that when it reaches 26, I would like it go back and continue the loop. For example, 25 is z, so 27 should be b.
Code:
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toLowerCase().toCharArray();
if (i < 0)
{
return null;
}
if(i > 25)
{
i = 0;
}
return Character.toString(alphabet[i]); //converts character to String and returns the character
}
You can use the modulo operation on i.
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toLowerCase().toCharArray();
int i =30;
System.out.println(alphabet[i % alphabet.length]);
You don't need any arrays or loops at all. Just do this:
return (char)('a' + (i % 26));
Try using a modulo operator for your indices. For example,
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toLowerCase().toCharArray();
if (i < 0) return;
i = i % 26;
return Character.toString(alphabet[i]);
Or
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toLowerCase().toCharArray();
if (i > 0)
return Character.toString(alphabet[i % 26]);
else
return;

Decrement only letters

I have to handle some strings, I should put them N positions to left to organize the string.
Here's my code for while:
private String toLeft() {
String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
byte lpad = 2; // Example
StringBuilder sb = new StringBuilder();
for (int i = 0; i < word.length(); i++) {
sb.append((char) (word.charAt(i) - lpad));
}
return sb.toString();
}
It's working for inputs that don't have to move many times...
So, the problem is that when the number N of positions to move is a little bit large (like 10), it returns me non letters, like in the example below, what can I do to prevent it?
Ex.: ABCDEFGHIJKLMNOPQRSTUVWXYZ if I move each char 10 positions to left it returns 789:;<=>?#ABCDEFGHIJKLMNOP while it must return QRSTUVWXYZABCDEFGHIJKLMNOP.
Some inputs and their expected outputs:
VQREQFGT // 2 positions to left == TOPCODER
ABCDEFGHIJKLMNOPQRSTUVWXYZ // 10 positions to left == QRSTUVWXYZABCDEFGHIJKLMNOP
LIPPSASVPH // 4 positions to left == HELLOWORLD
I think you have misunderstood what your (homework?) requirements are asking you to do. Lets look at your examples:
VQREQFGT // 2 positions to left == TOPCODER
Makes sense. Each character in the output is two characters before the corresponding input. But read on ...
ABCDEFGHIJKLMNOPQRSTUVWXYZ // 10 positions to left == QRSTUVWXYZABCDEFGHIJKLMNOP
Makes no sense (literally). The letter Q is not 10 characters before A in the alphabet. There is no letter in the alphabet that is before A in the alphabet.
OK so how do you get from A to Q in 10 steps?
Answer ... you wrap around!
A, Z, Y, X, W, V, U, T, S, R, Q ... 10 steps: count them.
So what the requirement is actually asking for is N characters to the left with wrap around. Even if they don't state this clearly, it is the only way that the examples "work".
But you just implemented N characters to the left without wrap around. You need to implement the wrap around. (I won't show you how, but there lots of ways to do it.)
There's another thing. The title of the question says "Decrement only letters" ... which implies to me that your requirement is saying that characters that are not letters should not be decremented. However, in your code you are decrementing every character in the input, whether or not it is a letter. (The fix is simple ... and you should work it out for yourself.)
what can I do to prevent it?
You make it wrap around.
If you want a value to go from 10 to 19 and then start at 10 again, in each iteration you subtract 10, increase by one, take the remainder of that divided by 20, and add 10 again.
Only here, 10 is 'A', 19 is Z, and instead of increasing by one, we add or subtract n.
private String toLeft() {
String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
byte lpad = 10; // Example
StringBuilder sb = new StringBuilder();
int n = -lpad; // I'm using n here to I can use '+ n' below
for (int i = 0; i < word.length(); i++) {
int shifted = word.charAt(i) - 'A' + n;
shifted %= ('Z' - 'A' + 1); // This is for positive n
while(shifted < 0) // And this for negative ones
{
shifted += ('Z' - 'A' + 1);
}
sb.append((char)(shifted + 'A'));
}
return sb.toString();
}
Please read #StephenC's excellent answer about wrap-around. In short, you don't shift left, you rotate left, such that B → A → Z → Y. When you rotate, you wrap around to the other end.
So, for letters you want A-Z to rotate. The easiest rotation method is using modulus (%).
Your logic will be as follows:
Convert letters A-Z into numbers 0-25: n = ch - 'A'
Apply shift and wrap around. Since you're shifting left, you're subtracting from the number, so to prevent negative numbers, you start by shifting a full cycle to the right: n = (n + 26 - shift) % 26
Convert numbers back to letters: ch = (char)(n + 'A')
Here is the code:
private static String rotateLeft(String text, int count) {
char[] buf = text.toCharArray();
for (int i = 0; i < buf.length; i++)
buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
return new String(buf);
}
Of course, you should validate input, and test your code:
private static String rotateLeft(String text, int count) {
char[] buf = text.toCharArray();
if (count <= 0 || count >= 26)
throw new IllegalArgumentException("Invalid count: " + count);
for (char ch : buf)
if (ch < 'A' || ch > 'Z')
throw new IllegalArgumentException("Invalid character: " + ch);
for (int i = 0; i < buf.length; i++)
buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
return new String(buf);
}
public static void main(String[] args) {
System.out.println(rotateLeft("VQREQFGT", 2));
System.out.println(rotateLeft("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10));
System.out.println(rotateLeft("LIPPSASVPH", 4));
}
OUTPUT
TOPCODER
QRSTUVWXYZABCDEFGHIJKLMNOP
HELLOWORLD

How to get alphabates letter number and operate on it [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have a requirement where I need to return the alphabet when given an alphabet and a number.
Example if given, C and 4 I will return C+4 = G
Also if given C and -2 I will return C + (-2) = A
If I have AA then, AA + 4 = AD, So I will always want to take the last character from the string.
I was thinking of using string array to store alphabets, but it seems kind of bad solution. Is there any way by which I can get it done better ?
Alphabet characters are all already in order, all you need to do is add a number to one to get another.
I presume you want something like this:
addToChar('A', 4);
char addToChar(char inChar, int inNum)
{
return (char)(inChar + inNum);
}
You may want to check whether it is less than 'A' or greater than 'Z' as well.
In response to your edit:
void addToChar(char[] inChars, int inNum)
{
for (int i = inChars.length-1; inNum != 0 && i >= 0; i--)
{
int result = inChars[i]-'A'+inNum;
if (result >= 0)
{
inNum = result / 26;
result %= 26;
}
else
{
inNum = 0;
while (result < 0) // there may be some room for optimization here
{
result += 26;
inNum--;
}
}
inChars[i] = (char)('A'+result);
}
}
To deal with overflow: (somewhat less efficient) ('Z' + 1 outputs 'AA')
static String addToChar(String inChars, int inNum)
{
String output = "";
for (int i = inChars.length()-1; inNum != 0 || i >= 0; i--)
{
if (i < 0 && inNum < 0)
return "Invalid input";
int result = i >= 0 ? inChars.charAt(i)-'A'+inNum
: -1+inNum;
if (result > 0)
{
inNum = result / 26;
result %= 26;
}
else
{
inNum = 0;
while (result < 0)
{
result += 26;
inNum--;
}
}
output = (char)('A'+result) + output;
}
return output;
}
try this for example :
public class example {
public static void main(String[] args) {
int number = 2;
char example = 'c';
System.out.println((char)(example+number));
}
}
this is an example for the updated question :
still need to verify the input number and input String (lets say what happens if the number is 124 ?)
public class example {
public static void main(String[] args) {
int number = 1;
String example = "nicd";
//get the last letter from the string
char lastChar = example.charAt(example.length()-1);
//add the number to the last char and save it
lastChar = (char) (lastChar+number);
//remove the last letter from the string
example = example.substring(0, example.length()-1);
//add the new letter to the end of the string
example = example.concat(String.valueOf(lastChar));
//will print nice
System.out.println(example);
}
}
Have you ever google about character set? Like ASCII, a character is already represented by a number.
You don't need to store alphabet letters in an array; this is one reason why ASCII has all letters in consecutive order.
Perform the math operation, which implicitly converts the char to an int, then cast the result to a char. You'll have to check that you don't go before 'A' or after 'Z'.
Here's an ASCII table reference.
First, convert your character to an int with a cast, then add your int, and convert it back to a char. For instance:
char c = 'c';
int cInt = (int)c;
int gInt = cInt + 4;
char g = (char)gInt; // 'G'

Categories