This is the multi-page printable view of this section. Click here to print.
Code War
- 1: FindPrime
- 2: GetMiddle
- 3: IsNarcissistic
- 4: NumberFun
- 5: Palindrome
- 6: PangramChecker
- 7: PhoneNumber
- 8: SpinWords
- 9: StringSplit
1 - FindPrime
DO NOT TRY to acquire fancy optimizations first
public static boolean isPrime(int num) {
// single exception
if (num == 2 || num == 5) {
return true;
} else if (num < 2) {
return false;
} // last digit exception
switch (num % 10) {
case 0:
case 2:
case 4:
case 5:
case 6:
case 8:
return false;
} // else
for (int i = 3; i <= Math.sqrt(num); i += 2) {
if (num % i == 0) {
return false;
} } return true;
}
2 - GetMiddle
Two main key-concepts
- length is odd get middle number of string
- length is even get middle 2 character
public static String getMiddle(String word) {
//Code goes here!
int length = word.length();
if(length == 0) return null;
return length%2 != 0 ? String.valueOf(word.charAt(length/2)) : word.substring(length/2-1,length/2+1);
}
Most part is return substring 2 characters. This method has complexity O(n)
We can improve to O(1), BY replacing substring to charAt
public static String getMiddle(String word) {
//Code goes here!
int length = word.length();
if(length == 0) return null;
return length%2 != 0 ? String.valueOf(word.charAt(length/2)) : word.charAt(length/2-1) + "" + word.charAt(length/2);
}
3 - IsNarcissistic
A Narcissistic Number (or Armstrong Number) is a positive number which is the sum of its own digits, each raised to the power of the number of digits in a given base. In this Kata, we will restrict ourselves to decimal (base 10).
For example, take 153 (3 digits), which is narcissistic:
1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153
and 1652 (4 digits), which isn’t:
1^4 + 6^4 + 5^4 + 2^4 = 1 + 1296 + 625 + 16 = 1938
The Challenge:
Your code must return true or false (not ’true’ and ‘false’) depending upon whether the given number is a Narcissistic number in base 10.
This may be True and False in your language, e.g. PHP.
Error checking for text strings or other invalid inputs is not required, only valid positive non-zero integers will be passed into the function
We just use MATH.POW for start
public static boolean isNarcissistic(int number) {
if(number < 0){
return false;
} int temp = number;
int sum = 0;
int count = String.valueOf(temp).length();
while(temp != 0) {
sum += Math.pow(temp % 10, count);
temp = temp / 10;
} boolean isNarcissistic = sum == number;
return isNarcissistic;
}}
Actually ,There are only few narcissistic numbers in the signed 32-bit with switch case, is easy to flow through all cases
public static boolean isNarcissistic(int number) {
switch (number) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 153:
case 370:
case 371:
case 407:
case 1_634:
case 8_208:
case 9_474:
case 54_748:
case 92_727:
case 93_084:
case 548_834:
case 1_741_725:
case 4_210_818:
case 9_800_817:
case 9_926_315:
case 24_678_050:
case 24_678_051:
case 88_593_477:
case 146_511_208:
case 472_335_975:
case 534_494_836:
case 912_985_153:
return true;
default:
return false;
}}
4 - NumberFun
You might know some pretty large perfect squares. But what about the NEXT one?
Complete the findNextSquare
method that finds the next integral perfect square after the one passed as a parameter. Recall that an integral perfect square is an integer n such that sqrt(n) is also an integer.
If the argument is itself not a perfect square then return either -1
or an empty value like None
or null
, depending on your language. You may assume the argument is non-negative.
https://www.codewars.com/kata/56269eb78ad2e4ced1000013
To be honest, there is no better way to utilize hardware instructions than by designing an algorithm yourself.
However, we can use an existing algorithm here.
public static long findNextSquare(long sq) {
// perfect number should end with 0, 9, 5, 4, 1
int back = (int)(sq % 10);
// indicate input is perfect square or not
if(back != 0 && back != 9 && back != 5 && back != 4 && back != 1 && back != 6){
return -1L;
}
// maybe a perfect number
else{
// find square root
// use repeated substraction
int factor = 1, i = 0;
while(sq > 0){
sq -= factor;
i++;
factor += 2;
}
long sqrt = i+1;
if(sq == 0) return sqrt*sqrt;
else return -1L;
}
}
Test cases
@Test
public void test1() {
assertEquals(144, NumberFun.findNextSquare(121));
}
@Test
public void test2() {
assertEquals(-1, NumberFun.findNextSquare(155));
}
@Test
public void test3() {
assertEquals(320356, NumberFun.findNextSquare(319225));
}
@Test
public void test4() {
assertEquals(15241630849L, NumberFun.findNextSquare(15241383936L));
}
@Test
public void test5() {
assertEquals(-1, NumberFun.findNextSquare(342786627));
}
@Test
public void randomTest1() {
long input = (long)(Math.random()*100000L)+1;
long square = input*input;
assertEquals(square+(input*2+1), NumberFun.findNextSquare(square));
}
The key part is type conversion—we need to convert int
to long
. Be careful, as the result of our calculation may exceed the range of int
.
For example:
return (long) * (long);
is different from
return (long)(int * int);
The latter may cause a loss of accuracy.
5 - Palindrome
String.Match()
ATM machines allow 4 or 6 digit PIN codes and PIN codes cannot contain anything but exactly 4 digits or exactly 6 digits.
If the function is passed a valid PIN string, return true
, else return false
.
two important cases
- no letters
- length limited
key: how to limit string in certain format
- ASII code to range numbers, use
String.length
to limit digits length
==be aware of ture and false== we can simply coding
// 1416ms
public static boolean validatePin(String pin) {
// Your code here...
int l = pin.length();
// boolean o = (l == 4) || (l == 6) ? true : false;
// boolean o = (l==4) || (l==6);
// for reach can't apply to string
for(char c : pin.toCharArray()) {
if(c<48 || c>57){
o = false;
} } return o;
}
- use built-in regex Patterns
String.match()
public static boolean validatePin(String pin) {
return pin.matches("\\d{4}|\\d{6}");
}
\d
means 0-9, but java can not use \d so replace with \\d
match 4 or 6 digits use \\d{4}
but remember no space before or after like
\\d{4}
or \\d{4}
- pre-compile to improve performance
we need compile patterns every time which is time-consuming with pre-compile we can save performance
static Pattern pattern = Pattern.compile("\\d{4}|\\d{6}");
public static boolean validatePin(String pin) {
// pre compile improve performance
return pattern.matcher(pin).matches();
}
test-case
@Test
public void validPins() {
assertEquals(true, Solution.validatePin("1234"));
assertEquals(true, Solution.validatePin("0000"));
assertEquals(true, Solution.validatePin("1111"));
assertEquals(true, Solution.validatePin("123456"));
assertEquals(true, Solution.validatePin("098765"));
assertEquals(true, Solution.validatePin("000000"));
assertEquals(true, Solution.validatePin("090909"));
}
@Test
public void nonDigitCharacters() {
assertEquals(false, Solution.validatePin(" a234"));
assertEquals(false, Solution.validatePin(".234"));
assertEquals(false, Solution.validatePin("utp4564utp"));
assertEquals(false, Solution.validatePin("newline"));
}
@Test
public void invalidLengths() {
assertEquals(false, Solution.validatePin("1"));
assertEquals(false, Solution.validatePin("12"));
assertEquals(false, Solution.validatePin("123"));
assertEquals(false, Solution.validatePin("12345"));
assertEquals(false, Solution.validatePin("1234567"));
assertEquals(false, Solution.validatePin(" 1234"));
assertEquals(false, Solution.validatePin(" 1234 "));
assertEquals(false, Solution.validatePin("1234 "));
assertEquals(false, Solution.validatePin("1.234"));
assertEquals(false, Solution.validatePin("00000000"));
assertEquals(false, Solution.validatePin("00000"));
assertEquals(false, Solution.validatePin("00000a"));
}
6 - PangramChecker
String.chars() Stream.map() Stream.distinct() Character.isAlphabetic()
Pre-pocess String. Use HashSet remove redundent numbers and non-alpha
public static boolean check(String sentence){
// sort chars in sentences
char[] charArray = sentence.toLowerCase().trim().toCharArray();
Arrays.sort(charArray);
HashSet<Character> set = new HashSet<>();
for (int i = 0; i < charArray.length; i++) {
if(set.contains(charArray[i])){
continue;
}else if(charArray[i] >= 97 && charArray[i] <= 122){
set.add(charArray[i]);
} } System.out.println(set);
return set.size() == 26;
}
That’s not beautiful enough, for removing we can use distinct()
and filter()
public static boolean check(String sentence) {
return sentence.chars().map(Character::toLowerCase).filter(Character::isAlphabetic).distinct().count() == 26;
}
But we can also check if sentence contain all A-Z, with a special for loop
public static boolean check(String sentence) {
sentence = sentence.toLowerCase().trim();
for (char c = 'a'; c < 'z'; c++) {
if (!sentence.contains("" + c)) {
return false;
} } return true;
}
Two solution have same complexity O(n), both are great.
7 - PhoneNumber
String.format()
First try, Prefixed numbers is fixed
we can simply cut out
public static String createPhoneNumber(int[] numbers) {
// Your code here!
String country = numbers[0] + "" + numbers[1] + "" + numbers[2];
String area = numbers[3] + "" + numbers[4] + "" + numbers[5];
String pop = "";
for (int i = 6; i <= numbers.length - 1; i++) {
pop = pop + numbers[i] + "";
} return "(" + country + ")" + " " + area + "-" + pop;
}
76ms
But There has an more elegant way to do so.
Use String.format()
public static String createPhoneNumber(int[] numbers){
return String.format("(%d%d%d) %d%d%d-%d%d%d%d",numbers[0],numbers[1],numbers[2],numbers[3],numbers[4],numbers[5],numbers[6],numbers[7],numbers[8],numbers[9] );
}
But this method have to compile formatter, which caused extra time.
Over all, we can use StringBuffer
to put Strings together.
public static String createPhoneNumber(int[] numbers) {
// Your code here!
return new StringBuilder()
.append("(")
.append(numbers[0])
.append(numbers[1])
.append(numbers[2])
.append(") ")
.append(numbers[3])
.append(numbers[4])
.append(numbers[5])
.append("-")
.append(numbers[6])
.append(numbers[7])
.append(numbers[8])
.append(numbers[9])
.toString();
}
76ms
Actually, It did not saving time, but use less space.
So recommend third method.
8 - SpinWords
StringBuilder.reverse()
String.join()
Test Sample is complex, we can process to beauty input
first try
public static String spinWords(String sentence) {
//TODO: Code stuff here
StringBuilder result = new StringBuilder();
StringBuilder word = new StringBuilder();
int count = 0;
for (int i = 0; i < sentence.length(); i++) {
char ch = sentence.charAt(i);
if (ch == ' ') {
if(count >= 5) {
result.append(reverse(word));
} else {
result.append(word.toString());
} result.append(" ");
word = new StringBuilder("");
count = 0;
continue;
} word.append(ch);
count++;
if (i == sentence.length() - 1) {
if(count >= 5) {
result.append(reverse(word));
} else result.append(word.toString());
} } return result.toString();
}
public static String reverse(StringBuilder word) {
StringBuilder result = new StringBuilder();
for (int i = word.length() - 1; i >= 0; i--) {
result.append(word.charAt(i));
} return result.toString();
}
That way too difficult. Actually, StringBuilder
has method reverse
we can preprocess to separated words, and join in space.
public static String spinWords(String sentence) {
//preprocess
String[] words = sentence.split(" ");
// what if replaced with enhanced-loop?
// words[i] is directly modified because we assign a new string to the same index in the array. //for(int i=0; i<words.length; i++) {
if (words[i].length() >= 5){
words[i] = new StringBuilder(words[i]).reverse().toString();
} } return String.join(" ", words);
}
9 - StringSplit
similar as GetMiddle
Different part is This kata need return all numbers (included ‘__’)
Add __ in front of loop
public static String[] solution(String s) {
//Write your code here
int l = s.length();
if(l%2 != 0){
s = s+"_";
l += 1;
} String[] result = new String[l/2];
int j = 0;
for(int i =0; i<=l-2;){
substring complexity is O(n)
result[j]=(s.substring(i,i+2));
i+=2;
j++;
} return result;
}
Same as [[GetMiddle]] we can replace substring with charAt
//34ms
public static String[] solution(String s) {
//Write your code here
int l = s.length();
if(l%2 != 0){
s = s+"_";
l += 1;
} String[] result = new String[l/2];
int j = 0;
for(int i =0; i<=l-2;){
result[j]=(s.charAt(i) + "" + s.charAt(i+1));
i+=2;
j++;
} return result;
}}
NOTE!!
String.substring()
have complexity of O(n), be careful when use it!