This is an interview question from
http://www.glassdoor.com/Interview/Indeed-Software-Engineer-Interview-Questions-EI_IE100561.0,6_KO7,24.htm , specifically, the problem
"The asked me a method that took in a string and return words up to the max length. There could be any amount of spaces which made it a little tricky "
Here is my solution(with test case)
public class MaxLength {
public static void main(String[] args) {
List<String> allWords = maxWords("Jasmine has no love for chris", 2);
for(String word: allWords){
System.out.println(word);
}
}
public static List<String> maxWords(String sentence, int length) {
String[] words = sentence.trim().split("\\s+");
List<String> list = new ArrayList<String>();
for(String word: words) {
if(word.length() <= length) {
list.add(word);
}
}
return list;
}
The test ran fine and i got my expected output - no. However during an actual interview, I think the interviewer doesn't expect you to know this regular expression off the top of your head (I didn't had to find it from How do I split a string with any whitespace chars as delimiters?)
Is there another approach to this problem without using regular expressions?
Try:
public static List<String> maxWords(String sentence, int length) {
List<String> list = new ArrayList<String>();
String tmp = sentence;
while (tmp.indexOf(" ") != -1) {
String word = tmp.substring(0,tmp.indexOf(" "));
tmp = tmp.substring(tmp.indexOf(" ")+1);
if(word.length() <= length) {
list.add(word);
}
}
return list;
}
You could use the StringTokenizer.
Another, maybe more lengthy approach would be to iterate over the string and use the methods provided by the Character class (Character.isWhiteSpace(char c)) and break the string accordingly.
Well, you could try something like this :
Doesn't create many subStrings() just creates subStrings of "matched" Strings
public class Test {
public static void main(String[] args) {
String s = "Jasmine has no love for chris";
s=s.trim();
List<String> ls = getMaxLength(s, 3);
for (String str : ls) {
System.out.println(str);
}
}
static List<String> getMaxLength(String s, int length) {
List<String> ls = new ArrayList<String>();
int i = 0;
if (s.charAt(i + length) == ' ' || i + length == s.length()) { // search if first word matches your criterion.
for (i = 1; i < length; i++) { // check for whitespace between 0 and length
if (s.charAt(i) == ' ') {
i = length;
break;
}
if (i == length - 1)
ls.add(s.substring(0, length));
}
}
for (i = length; i < s.length(); i++) {// start search from second word..
if (s.charAt(i - 1) == ' ' && i + length < s.length() // if char at length is space or end of String, make sure the char before the current char is a space.
&& (s.charAt(i + length) == ' ' || i + length == s.length())) {
for (int j = i; j < i + length; j++) {
if (s.charAt(j) == ' ') {
i = i + length;
break;
}
if (j == i + length - 1) {
ls.add(s.substring(i, i + length));
}
}
}
}
return ls;
} // end of method
}
Related
I want to check if every word in an string has specific endings with various length. I can't use arrays & methods for this like endsWith(). The only methods im allowed to use are charAt() and length().
public class TextAnalyse {
public static void main(String[] args) {
System.out.println(countEndings("This is a test", "t"));
System.out.println(countEndings("Waren sollen rollen", "en"));
System.out.println(countEndings("The ending is longer then every single word", "abcdefghijklmn"));
System.out.println(countEndings("Today is a good day", "xyz"));
System.out.println(countEndings("Thist is a test", "t"));
System.out.println(countEndings("This is a test!", "t"));
System.out.println(countEndings("Is this a test?", "t"));
}
public static int countEndings(String text, String ending) {
int counter = 0;
int counting;
int lastStringChar;
for (int i = 0; i < text.length(); i++) {
lastStringChar = 0;
if (!(text.charAt(i) >= 'A' && text.charAt(i) <= 'Z' || text.charAt(i) >= 'a' && text.charAt(i) <= 'z') || i == text.length() - 1) {
if( i == text.length() - 1 ){
lastStringChar = 1;
}
counting = 0;
for (int j = 0; j + lastStringChar < ending.length() && i > ending.length(); j++) {
if (text.charAt(i - ending.length() + j + lastStringChar) == ending.charAt(j)) {
counting = 1;
} else {
counting = 0;
}
}
counter += counting;
}
}
return counter;
}
}
The actual results are that I get one counting less, I guess its because it dont check the last chars properly.
The most simple solution I can come up with is the following:
Check, if a word ends with a given suffix:
public static boolean endsWith(String word, String suffix) {
if(suffix.length() > word.length()) {
return false;
}
int textIndex = (word.length() - 1);
int suffixIndex = (suffix.length() - 1);
while(suffixIndex >= 0) {
char textChar = word.charAt(textIndex);
char suffixChar = suffix.charAt(suffixIndex);
if(textChar != suffixChar) {
return false;
}
textIndex--;
suffixIndex--;
}
return true;
}
Split the given in its' words and use the above method to count every word ending with the given ending:
public static int countEndings(String text, String ending) {
{
//maybe remove punctuation here...
//(if yes, use String.replace for example)
}
String[] words = text.split(" ");
int counter = 0;
for(String word: words) {
if(endsWith(word, ending)) {
counter++;
}
}
return counter;
}
Also consider to remove unwanted punctuation, like '!' or '?' (...) - the above implementation will not recognize count any word ending with t in the String test!!
I guess you are able to use regular expression.
If you want count words with ending, you can use the following code:
public static int countEndings(String text, String ending) {
final Matcher wordWithEndMatches = Pattern.compile("\\b[A-Za-z]*" + ending + "\\b").matcher(text);
int count = 0;
while(wordWithEndMatches.find()) {
count++;
}
return count;
}
I've tried to create a method that takes in an array of strings and returns a single formatted string.
The last word should be separated by the word 'and' instead of a comma.
But it doesn't work as expected :)
It doesn't replace the last comma by the word "and".
Can you please advise where is my mistake.
thanks.
public class Kata {
public static String formatWords(String[] words) {
List<String> words1 = Arrays.asList(words);
ListIterator<String> wordIter = words1.listIterator();
StringBuilder out = new StringBuilder();
while (wordIter.hasNext()) {
out.append(wordIter.next());
if (wordIter.hasNext()) {
out.append(",");
}
}
return out.toString().replaceAll(",$", "and");
}
}
Since you may have empty items, first use a list to clear the empty items:
public static String formatWords(String[] words) {
if (words == null)
return "";
List<String> list = new ArrayList<>();
for (String word : words) {
word = word.trim();
if (!word.isEmpty())
list.add(word);
}
StringBuilder out = new StringBuilder();
int len = list.size();
for (int i = 0; i < len; i++) {
out.append(list.get(i));
if (i == len - 2)
out.append(" and ");
else if (i < len - 2)
out.append(",");
}
return out.toString();
}
public static void main(String[] args) {
String[] array = {"", "apples", "", "oranges", "", "melons", ""};
System.out.println(formatWords(array));
}
will print:
apples,oranges and melons
I'd iterate up to the before-last element and concat the strings with commas, and then concat the last one with an "and":
public static String formatWords(String[] words) {
// Handle nulls and empty arrays
if (words == null || words.length) {
return "";
}
// Handle the first word
StringBuilder sb = new StringBuilder(words[0]);
// Handle all the words from the second to the before last
for (int i = 1; i < words.lengh - 1; ++i) {
sb.append(", ").append(word[i]);
}
// Check that there are at least two words
if (words.length > 1) {
// Handle the last word with an "and"
sb.append(" and ").append(words[1])
}
}
you don't need to use List and ListIterator (in this case!)
this is my solution!
ps: I don't undestand why the method is Static, i think in this casa is not necessary because we don't work on any static variables.
public static String formatWords(String[]words){
//Usefull to build the final resoult
StringBuilder sb = new StringBuilder();
/*start to put the word in the string builder
from the first to the last*/
for (int i = 0; i < words.length; i++) {
//put the wordat position i in string builder
sb.append(words[i]);
/*if the word is the 2 last and there are egual or more than
2 elements in words array
we can add the "and"*/
if(i==words.length-2 && words.length>=2) {
sb.append(" and ");
/*if the word is not the last put a comma
(actually we put a comma when there are more thand 3 item in words, but not in the last)
*/
}else if(i<words.length-1 ){
sb.append(", ");
}
/*if word[i] is the last of the array words we don't use nobody of the if!*/
/*this code word on 0 1,2,3 ore more word in array words!*/
}
return sb.toString();
}
replaceAll(",$", "and"); doesn't do what you think. It cannot find the last , in the string.
Try this
while(wordIter.hasNext()) {
//your code
}
if (words.length > 1) {
int indexOfLastComma = out.length() - words[words.length - 1].length();
return out.replace(indexOfLastComma - 1, indexOfLastComma, " and ").toString();
}
return out.toString();
We find the index of the last Comma and then replace it with and in its place.
Here's a fun way using Streams
String tempResult = IntStream.range(0, words.length - 1)
.mapToObj(i -> words[i])
.collect(Collectors.joining(","));
return words.length > 1 ? tempResult + " and " + words[words.length - 1] : words[0];
EDIT:
To filter out empty words, you can use a filter. Now checking words.length > 1 at the end will no longer work (since it can have empty strings). So, I'm checking if the tempResult has atleast one ,.
Here is a complete solution
String tempResult = Arrays.stream(words)
.filter(word -> !word.isEmpty())
.collect(Collectors.joining(","));
int indexOfLastComma = tempResult.lastIndexOf(',');
return indexOfLastComma != -1 ? tempResult.substring(0, indexOfLastComma) + " and "
+ tempResult.substring(indexOfLastComma + 1): tempResult;
It creates substring - so not the most efficient solution.
I have somehow got the output with the help of some browsing. But I couldn't understand the logic behind the code. Is there any simple way to achieve this?
public class LetterCount {
public static void main(String[] args)
{
String str = "aabbcccddd";
int[] counts = new int[(int) Character.MAX_VALUE];
// If you are certain you will only have ASCII characters, I would use `new int[256]` instead
for (int i = 0; i < str.length(); i++) {
char charAt = str.charAt(i);
counts[(int) charAt]++;
}
for (int i = 0; i < counts.length; i++) {
if (counts[i] > 0)
//System.out.println("Number of " + (char) i + ": " + counts[i]);
System.out.print(""+ counts[i] + (char) i + "");
}
}
}
There are 3 conditions which need to be taken care of:
if (s.charAt(x) != s.charAt(x + 1) && count == 1) ⇒ print the counter and character;
if (s.charAt(x) == s.charAt(x + 1)) ⇒ increase the counter;
if (s.charAt(x) != s.charAt(x + 1) && count >= 2) ⇒ reset to counter 1.
{
int count= 1;
int x;
for (x = 0; x < s.length() - 1; x++) {
if (s.charAt(x) != s.charAt(x + 1) && count == 1) {
System.out.print(s.charAt(x));
System.out.print(count);
}
else if (s.charAt(x)== s.charAt(x + 1)) {
count++;
}
else if (s.charAt(x) != s.charAt(x + 1) && count >= 2) {
System.out.print(s.charAt(x));
System.out.print(count);
count = 1;
}
}
System.out.print(s.charAt(x));
System.out.println(count);
}
The code is really simple.It uses the ASCII value of a character to index into the array that stores the frequency of each character.
The output is simply got by iterating over that array and which character has frequency greater than 1, print it accordingly as you want in the output that is frequency followed by character.
If the input string has same characters consecutive then the solution can be using space of O(1)
For example in your string aabbcc, the same characters are consecutive , so we can take advantage of this fact and count the character frequency and print it at the same time.
for (int i = 0; i < str.length(); i++)
{
int freq = 1;
while((i+1)<str.length()&&str.charAt(i) == str.charAt(i+1))
{++freq;++i}
System.out.print(freq+str.charAt(i));
}
You are trying to keep count of the number of times each character is found. An array is referenced by an index. For example, the ASCII code for the lowercase letter a is the integer 97. Thus the count of the number of times the letter a is seen is in counts[97]. After every element in the counts array has been set, you print out how many have been found.
This should help you understand the basic idea behind how to approach the string compression problem
import java.util.*;
public class LetterCount {
public static void main(String[] args) {
//your input string
String str = "aabbcccddd";
//split your input into characters
String chars[] = str.split("");
//maintain a map to store unique character and its frequency
Map<String, Integer> compressMap = new LinkedHashMap<String, Integer>();
//read every letter in input string
for(String s: chars) {
//java.lang.String.split(String) method includes empty string in your
//split array, so you need to ignore that
if("".equals(s))
continue;
//obtain the previous occurances of the character
Integer count = compressMap.get(s);
//if the character was previously encountered, increment its count
if(count != null)
compressMap.put(s, ++count);
else//otherwise store it as first occurance
compressMap.put(s, 1);
}
//Create a StringBuffer object, to append your input
//StringBuffer is thread safe, so I prefer using it
//you could use StringBuilder if you don't expect your code to run
//in a multithreaded environment
StringBuffer output = new StringBuffer("");
//iterate over every entry in map
for (Map.Entry<String, Integer> entry : compressMap.entrySet()) {
//append the results to output
output.append(entry.getValue()).append(entry.getKey());
}
//print the output on console
System.out.println(output);
}
}
class Solution {
public String toFormat(String input) {
char inChar[] = input.toCharArray();
String output = "";
int i;
for(i=0;i<input.length();i++) {
int count = 1;
while(i+1<input.length() && inChar[i] == inChar[i+1]) {
count+=1;
i+=1;
}
output+=inChar[i]+String.valueOf(count);
}
return output;
}
public static void main(String[] args) {
Solution sol = new Solution();
String input = "aaabbbbcc";
System.out.println("Formatted String is: " + sol.toFormat(input));
}
}
def encode(Test_string):
count = 0
Result = ""
for i in range(len(Test_string)):
if (i+1) < len(Test_string) and (Test_string[i] == Test_string[i+1]):
count += 1
else:
Result += str((count+1))+Test_string[i]
count = 0
return Result
print(encode("ABBBBCCCCCCCCAB"))
If you want to get the correct count considering the string is not in alphabetical order. Sort the string
public class SquareStrings {
public static void main(String[] args) {
SquareStrings squareStrings = new SquareStrings();
String str = "abbccddddbd";
System.out.println(squareStrings.manipulate(str));
}
private String manipulate(String str1) {
//convert to charArray
char[] charArray = str1.toCharArray();
Arrays.sort(charArray);
String str = new String(charArray);
StringBuilder stbuBuilder = new StringBuilder("");
int length = str.length();
String temp = "";
if (length > 1) {
for (int i = 0; i < length; i++) {
int freq = 1;
while (((i + 1) < length) && (str.charAt(i) == str.charAt(i + 1))) {
++freq;
temp = str.charAt(i) + "" + freq;
++i;
}
stbuBuilder.append(temp);
}
} else {
return str + "" + 1;
}
return stbuBuilder.toString();
}
}
Kotlin:
fun compressString(input: String): String {
if (input.isEmpty()){
return ""
}
var result = ""
var count = 1
var char1 = input[0]
for (i in 1 until input.length) {
val char2 = input[i]
if (char1 == char2) {
count++
} else {
if (count != 1) {
result += "$count$char1"
count = 1
} else {
result += "$char1"
}
char1 = char2
}
}
result += if (count != 1) {
"$count$char1"
} else {
"$char1"
}
return result
}
I have this code that is supposed to do what the title said, reverse the order of characters without changing the order of the words:
package stackTests;
import java.util.Scanner;
import java.util.Stack;
public class StackTest
{
Stack<Character> stack;
public StackTest()
{
stack = new Stack<Character>();
}
public String reverseString(String str)
{
int start = 0;
int start2 = 0;
int size;
char space = ' ';
char[] cArr;
Scanner scan = new Scanner(str);
cArr = str.toCharArray();
for (; start < cArr.length; start++)
{
if(cArr[start] == space || start == cArr.length - 1)
{
for (; start2 < stack.size(); start++)
{
System.out.print(stack.pop());
}
}
else
{
stack.push(cArr[start]);
}
start2 = 0;
}
return str;
}
}
It works fine if I enter a single word like "Hello"--it will output "olleH"--but as soon as it gets more complicated than one word it starts to output some weird things."Hello my name is" outputs "ollehem". I'm really new to Stacks and this is my first time using them. I'm not sure if there is a logic error or improper use of Stacks.
you're not outputting original spaces, this is why you're seeing strange results
here is fixed version:
public static void reverseString(final String str) {
final Stack<Character> stack = new Stack<>();
for (int i = 0; i < str.length(); i++) {
final char c = str.charAt(i);
if (c == ' ') {
while (!stack.isEmpty())
System.out.print(stack.pop());
System.out.print(' ');
} else
stack.push(c);
}
while (!stack.isEmpty())
System.out.print(stack.pop());
}
another version without stack, with in-place replacement:
public static void reverseString(final String str) {
final char[] chars = str.toCharArray();
int start = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ' ') {
reverse(chars, start, i - 1);
start = i + 1;
}
}
reverse(chars, start, chars.length - 1);
System.out.println(new String(chars));
}
private static void reverse(final char[] chars, int s, int e) {
while (s < e) {
final char t = chars[s];
chars[s] = chars[e];
chars[e] = t;
s++;
e--;
}
}
If you HAVE to use a stack, I would follow an algorithm like this:
String myString = "Hello World";
Stack<Character> stack = new Stack<Character>();
StringBuilder sb = new StringBuilder();
String[] splitString = myString.split(" ");
//Iterate through each word in the string
for(String s : splitString){
//Push each character of the word into LIFO stack
for(char c : s.toCharArray()){
stack.push(c);
}
//Build new string with reverse ordered characters
while(!stack.isEmpty()){
sb.append(stack.pop());
}
//Append a space as long as it's not the last word of the original string
if(!s.equals(splitString[splitString.length - 1]))
sb.append(" ");
}
//Print the new string
System.out.println(sb.toString());
I'm not sure efficiency matters to you, but this algorithm would work in linear time, where n is the number of characters in the string.
Here is how you can do it in-place without using any extra space (Not using stack):
public class ReverseWordsInplace {
public static void main(String[] args) {
reverseWords(new StringBuilder("This is a test"));
}
public static void reverseWords(StringBuilder s) {
StringBuilder str = new StringBuilder(s);
int startWordIndex = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == ' ' || str.length() - 1 == i) {
int x = 0;
int endWordIndex = str.charAt(i) == ' ' ? i - 1 : i;
while (endWordIndex - x > startWordIndex + x) {
char c1 = str.charAt(startWordIndex + x);
char c2 = str.charAt(endWordIndex - x);
str.setCharAt(startWordIndex + x, c2);
str.setCharAt(endWordIndex - x, c1);
x++;
}
startWordIndex = i + 1;
}
}
System.out.println(str);
}
}
Output:
sihT si a tset
I've been really struggling with a programming assignment. Basically, we have to write a program that translates a sentence in English into one in Pig Latin. The first method we need is one to tokenize the string, and we are not allowed to use the Split method usually used in Java. I've been trying to do this for the past 2 days with no luck, here is what I have so far:
public class PigLatin
{
public static void main(String[] args)
{
String s = "Hello there my name is John";
Tokenize(s);
}
public static String[] Tokenize(String english)
{
String[] tokenized = new String[english.length()];
for (int i = 0; i < english.length(); i++)
{
int j= 0;
while (english.charAt(i) != ' ')
{
String m = "";
m = m + english.charAt(i);
if (english.charAt(i) == ' ')
{
j++;
}
else
{
break;
}
}
for (int l = 0; l < tokenized.length; l++) {
System.out.print(tokenized[l] + ", ");
}
}
return tokenized;
}
}
All this does is print an enormously long array of "null"s. If anyone can offer any input at all, I would reallllyyyy appreciate it!
Thank you in advance
Update: We are supposed to assume that there will be no punctuation or extra spaces, so basically whenever there is a space, it's a new word
If I understand your question, and what your Tokenize was intended to do; then I would start by writing a function to split the String
static String[] splitOnWhiteSpace(String str) {
List<String> al = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (char ch : str.toCharArray()) {
if (Character.isWhitespace(ch)) {
if (sb.length() > 0) {
al.add(sb.toString());
sb.setLength(0);
}
} else {
sb.append(ch);
}
}
if (sb.length() > 0) {
al.add(sb.toString());
}
String[] ret = new String[al.size()];
return al.toArray(ret);
}
and then print using Arrays.toString(Object[]) like
public static void main(String[] args) {
String s = "Hello there my name is John";
String[] words = splitOnWhiteSpace(s);
System.out.println(Arrays.toString(words));
}
If you're allowed to use the StringTokenizer Object (which I think is what the assignment is asking, it would look something like this:
StringTokenizer st = new StringTokenizer("this is a test");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
which will produce the output:
this
is
a
test
Taken from here.
The string is split into tokens and stored in a stack. The while loop loops through the tokens, which is where you can apply the pig latin logic.
Some hints for you to do the "manual splitting" work.
There is a method String#indexOf(int ch, int fromIndex) to help you to find next occurrence of a character
There is a method String#substring(int beginIndex, int endIndex) to extract certain part of a string.
Here is some pseudo-code that show you how to split it (there are more safety handling that you need, I will leave that to you)
List<String> results = ...;
int startIndex = 0;
int endIndex = 0;
while (startIndex < inputString.length) {
endIndex = get next index of space after startIndex
if no space found {
endIndex = inputString.length
}
String result = get substring of inputString from startIndex to endIndex-1
results.add(result)
startIndex = endIndex + 1 // move startIndex to next position after space
}
// here, results contains all splitted words
String english = "hello my fellow friend"
ArrayList tokenized = new ArrayList<String>();
String m = "";
int j = 0; //index for tokenised array list.
for (int i = 0; i < english.length(); i++)
{
//the condition's position do matter here, if you
//change them, english.charAt(i) will give index
//out of bounds exception
while( i < english.length() && english.charAt(i) != ' ')
{
m = m + english.charAt(i);
i++;
}
//add to array list if there is some string
//if its only ' ', array will be empty so we are OK.
if(m.length() > 0 )
{
tokenized.add(m);
j++;
m = "";
}
}
//print the array list
for (int l = 0; l < tokenized.size(); l++) {
System.out.print(tokenized.get(l) + ", ");
}
This prints, "hello,my,fellow,friend,"
I used an array list since at the first sight the length of the array is not clear.