This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 years ago.
So I've been trying to solve the word break Dynamic Programming problem, which basically means that given a dictionary of strings and a string, see if the words in the dictionary can be combined to form the string. For example, given word "applepenapple" and dictionary ["apple","pen"] it should return true.
I have a working java solution, but I'm trying to improve my C++ skills. My problem is even though my code looks extremely similar to the working solution in Java, I am failing a niche test case and I can't figure out why.
C++ code:
bool wordBreak(string s, vector<string> &wordDict) {
vector<int> bArr(s.length(), -1);
unordered_set<string> set(wordDict.begin(), wordDict.end());
return wordBreak(s, bArr, 0, set);
}
bool wordBreak(string s, vector<int> &bArr, int start, unordered_set<string> &set) {
if (start == s.length())
return true;
//If we have a memoized solution to this problem, avoid recurion
if (bArr[start] != -1)
return (bArr[start] == 1);
for (int end = start + 1; end <= s.length(); end++) {
if (set.count(s.substr(start, end)) && wordBreak(s, bArr, end, set)) {
bArr[start] = 1;
return bArr[start] == 1;
}
}
bArr[start] = 0;
return false;
}
Working code using java:
public boolean wordBreak(String s, List<String> wordDict) {
Integer[] memo =new Integer[s.length()];
Arrays.fill(memo,-1);
return word_Break(s, new HashSet(wordDict), 0, memo);
}
public boolean word_Break(String s, Set<String> wordDict, int start, Integer[] memo) {
if (start == s.length()) {
return true;
}
if (memo[start] != -1) {
return memo[start]==1;
}
for (int end = start + 1; end <= s.length(); end++) {
if (wordDict.contains(s.substring(start, end)) && word_Break(s, wordDict, end, memo)) {
memo[start] = 1;
return memo[start] == 1;
}
}
memo[start] = 0;
return false;
}
The C++ code is returning false for "applepenapple" with dictionary ["apple","pen"] and I don't know why since the java return true which is correct. The only major difference (I think) between the two solutions is that my C++ uses a vector instead of a native array in the java code. Initially I thought it might have to do with C++ using automatic storage (stack) vs the free store (heap) which is why I used the vector instead of a C-style array to avoid memory management because of RAII. Despite this change, the bug persists. There is an easier solution avoiding recursion altogether, but I am very curious as to why the C++ is returning different output than the java.
I see a potential problem. From java.lang.String Javadoc (emphasis mine):
public String substring(int beginIndex, int endIndex)
Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.
Examples:
"hamburger".substring(4, 8) returns "urge"
"smiles".substring(1, 5) returns "mile"
Parameters:
beginIndex - the beginning index, inclusive.
endIndex - the ending index, exclusive.
From cppreference.com documentation on strings:
basic_string substr( size_type pos = 0, size_type count = npos ) const;
Returns a substring [pos, pos+count). If the requested substring extends past the end of the string, or if count == npos, the returned substring is [pos, size()).
Parameters
pos - position of the first character to include
count - length of the substring
That is, in Java you should pass an index as second parameter to String.substring(...), but in C++ you should pass a length to basic_string::substr(...). However, you are doing:
s.substr(start, end)
and
s.substring(start, end)
in both cases.
Maybe adjusting the C++ invocation to
s.substr(start, end - start)
will work?
Related
When working with a StringBuilder, I often append 2 char values to a StringBuilder using StringBuilder#append(char) twice, rather than StringBuilder#append(String).
I.e.:
StringBuilder builder = new StringBuilder();
builder.append(' ').append('t'); // would append(" t") work better here?
return builder.toString();
I would like to know:
Which approach is better performance-wise
Which approach is more common and why
I have already read through Using character instead of String for single-character values in StringBuffer append but it does not answer my question.
That question pertains to whether appending a single character (append('c')) is better than a single-character string (append("c")). I already understand why appending a single character is better than a single-character string, but I do not know whether appending a two-character string (append("ab")) is better than twice appending each character (append('a').append('b')).
In my testing, both of them seemed to take about the same time, however appending a string might be slightly slower (maybe 10 or so nanoseconds)
However, appending a string is much more popular as it's easier to use/understand.
This is really interesting to figure out this one.
As we all know the array is fast and internally String is using Character Array for storing the values.
internally both the method called the super.append(XXX) method ofAbstractStringBuilderclass.
if you see the code of append in AbstractStringBuilder for String and CharSeq
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
count += len;
return this;
}
These are the method internally called when you call append method.
Both the method calls the ensureCapacityInternal method to expand the array. So let's leave this method call as it is.
Now, the main difference comes in the next line of code.
The method with String args calls the getChars method. which internally call the System.arraycopy method, it's a native method and we can't predict the complexity of that method. it's based on the OS/JVM.
CharSeq method uses a for loop till the length of input charSequence.
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
i.e. it's completixity is depend on the length of input.
As I study, Other posts related to System.arraycopy method. They all say that it's effective than copying an array by a loop. even in an Effective Java Programing book.
So finally opinion, I would suggest that if the input is of small length then use the CharSequence only. Why waste the JVM for the small length String.
If you have long length string like a statement then go for a method with String args. Also, remember Space complexity increases in this case. i.e. String is immutable and you are creating more String every time in a pool. String.valueof(), (String)obj are examples.
Edited:
public AbstractStringBuilder append(char c) { ensureCapacityInternal(count + 1); value[count++] = c; return this; }
This method used when the args is char.
And seems that. It's more fast then others.
Because of assignment at count++ index of char. This method only contain the system.arraycopy method, which is common in all other method for ensuringcapacity.
Hope this will help. :)
I need to count the occurrences of a substring in a larger string in Java using recursion. I get the idea of recursion, but I'm not sure how it applies to problems like these. Does anyone know how to do this?
I have a lot of similar problems too. Any advice for solving a general problem recursively? My biggest concern is finding the base case.
Thanks!
There's no really general way of doing it, I don't think. But here's how I'd do it for this problem:
You wouldn't actually solve this using recursion (in Java, at least). You'd write something like this:
int countOccurrences(String str, String search) {
int count = 0;
int i = 0;
while (true) {
i = str.indexOf(search, i);
if (i == -1) {
break;
} else {
count += 1;
i += search.length();
}
}
return count;
}
So, you can rewrite this as a tail recursion, something like:
int countOccurrences(String str, String search) {
return recurse(str, search, 0, 0);
}
int recurse(String str, String search, int count, int i) {
i = str.indexOf(search, i);
if (i == -1) {
// Like the while loop where i == -1, i.e. no more occurrences found.
// Break the recursion.
return count;
} else {
// Like the while loop where i != -1: an occurrence was found.
// Increment count, and keep on searching.
return recurse(str, search, count + 1, i + search.length());
}
}
Hopefully you can see the commonality between the loop and recursive approaches.
Note that you don't need to write a tail recursion: you can write a non-tail recursion by dropping the count parameter from the recurse method, and making the non-terminal case:
return 1 + recurse(str, search, i + search.length());
It doesn't make too much of a difference in Java, which doesn't perform tail call optimization, but the tail recursive form may be more efficient in other languages (where it can be converted back into a loop, as above).
in java,
String month= "November 2014";
for making a substring giving the index from right hand side, I cannot use
someString.substring(-4);
as negative values are not supported.
Is there any simple implementation I can use to achieve this.
No, negative numbers are not allowed (it would throw a StringIndexOutOfBoundsException). You can use this:
if(month.length() >= 4) {
year = month.substring(month.length() - 4);
}
I love Python's indexing and prefer to be able to use it in Java as well ;)
A general implementation of substring with support for negative indexing could be implemented like this:
A method for converting negative indexes to their positive equivalent is useful:
private static int toPosIndex(String str, int index) {
if (index >= 0) return index;
else return str.length() + index;
This method can then be used to declare a substring method with support for negative indexes:
public static String negSubstring(String str, int index1, int index2) {
return str.substring(toPosIndex(str, index1), toPosIndex(str, index2));
}
and if needed an equivalent to the version of substring with only one index parameter:
public static String negSubstring(String str, int index) {
return str.substring(toPosIndex(str, index));
}
(I realise the question is more than two years old, but figured that other new users might be interested in a general answer to the question).
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
when given a input string i am suppose to break it up into two groups
char
int.
with these two groups i want to create a new alternating string.
for example
abc1234defgh567jk89
will transform into
a1b2c3d5e6f7j8k9
notice that the digit 4,g,h has been discarded.
i figured that a queue can be implemented in this case.
queue1> abc
queue2> 123
index 0 to 2 is a char
index three is a int, so for queue 2 we only take in 3 values.
my question is there a more efficient data structure to perform this operation?
and during implementation, how to i compare to see if a particular value is a int or a char?
please advise.
Treating the string as an array of char integers would make this easier to compare, as you can do a simple comparision on the entry. If array[x]>64 it is a character else it is a number. You can use two pointers to do the interleaving. One for character and the other for integer. Find a character and then advance the integer pointer until it finds a match, then advance them as long as they are both true, then fast forward both of them. For example:
char array[]=(char *)string;
int letter=array[0];
int number=array[0];
// Initialize
while(number >= 64)
number++;
while (letter<64)
letter++;
//Now that the pointers are initialized, interleave them.
while(letter>=64 && number<64)
{
output[i++]=letter;
output[i++]=number;
number++;
letter++;
}
// Now you need to advance to the next batch, so you need to see the comparison false and then true again.
....
You are right, a queue is a good data structure for this problem. If, however, you want fancier methods at hand, a Linked List would be another very similar alternative.
To check if a particular value is a letter or a number, you can use the Character class. For example,
String sample = "hello1";
Character.isLetter( sample.charAt(0) ); // returns true
Character.isLetter( sample.charAt(5) ); // returns false
how to i compare to see if a particular value is a int or a char?
You can do something like this:
String string = "abc1234defgh567jk89";
for(int i=0; i<string.length;i++){
int c = (int)string.charAt(i);
boolean isChar = 97<=c&&c<=122 || 65<=c&&c<=90;
boolean isNum = 48<=c&&c<=57;
if(!isChar && !isNum){
throw new IllegalArgumentException("I don't know what you are")
}
}
About the datastructutures, personally I will use two single linked list, one for chars and one for numbers and every character will be stored in a different node. Why?, well if you store the characters (in general, I mean chars and ints) in groups of threes later you will have to add more code to split those groups and put chars and ints together, putting them in a linked list makes sense because
you can put as much nodes as you want (or memory lets you but let's assume is infinite)
data will be stored in order (which looks like some kind of requirement you have in order to display the output, also this discards trees and stacks(FILO))
since you only need to go forward when generating the output a double linked list will be over engineering.
To generate the output:
Having two datastructures let's you add another check like:
if(listChars.size() != listNums.size()){
throw new IllegalArgumentException("Wrong input!!!")
}
Additionally,
Reviewing the list will take you O(n) time, memory used will be O(n), reviewing both list will take you O(n/m) where m is the size of the initial group of chars.
You can do that like this:
Iterator<Character> iterChar = listChar.iterator();
Iterator<Integer> iterNum = listChar.iterator();
String result = "";
while(iterChar.hasNext() && iterNum.hasNext() ){
result+=iterChar.next()+iterNum.next();
}
Finally, you can use queues or linked list here both give you the same in this scenario
To check if the next char is a letter or number you can use this:
public static boolean isNumber(char c) { return c >= '0' && c <= '9'; }
public static boolean isLetter(char c) { return c >= 'a' && c <= 'z'; }
These functions find the index of the next number or letter, starting at pos i:
public static int nextNumber(String s, int i) {
while(i < s.length() && !isNumber(s.charAt(i))) i++;
return i;
}
public static int nextLetter(String s, int i) {
while(i < s.length() && !isLetter(s.charAt(i))) i++;
return i;
}
You don't really need a data structure, all you need is 3 pointers:
public static String alternate(String s){
// pointers
int start = 0, mid = 0, end = 0;
StringBuilder sb = new StringBuilder(s.length());
while(end < s.length()){
// E.g. for 'abc1234' {start, mid, end} = {0, 3, 7}
start = Math.min(nextLetter(s, end), nextNumber(s, end));
mid = Math.max(nextLetter(s, end), nextNumber(s, end));
end = Math.max(nextLetter(s, mid), nextNumber(s, mid));
for(int i = 0; i < Math.min(mid - start, end - mid); i++)
sb.append(s.charAt(start + i)).append(s.charAt(mid + i));
}
return sb.toString();
}
Running the example below outputs the desired result: a1b2c3d5e6f7j8k9
public static void main(String... args){
System.out.println(alternate("abc1234defgh567jk89"));
}
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Programming java to determine a symmetrical word
am new here, but I am having hard time figuring out how to write a code to determine an input of word and see if the first is matching with the end of the word. You may input abba and get answer it's evenly symmetric and aba is oddly symmetric.
Please show me how:(
Just two main things.
first I want to know if it's oddly or evenly amount of letter(number of letter divided by 2,if it's ending with 0.5, it's oddly symmetric, if is an integer it's evenly symmetric.
second I want to get (i.e 1=n,2=n-1,3=n-2...) position of the letter in the word to be the main idea of the execution.If there is a last letter in the oddly symmetric word, ignore the last remaining letter.
I appreciate any headstart or idea:) Thanks!
Thanks KDiTraglia, I made the code and compiled and here is what I put. I am not getting any further.
Reported problem:
Exception in thread "main" java.lang.Error: Unresolved compilation problems: reverse cannot be resolved or is not a field reverse cannot be resolved or is not a field Syntax error, insert ") Statement" to complete IfStatement
This is what i got from, KDiTraglia's help
public class WordSymmetric {
public static void main(String[] args) {
String word = "abccdccba";
if ( (word.length() % 2) == 1 ) {
System.out.println("They are oddly symmetric");
//odd
}
else {
System.out.println("They are evenly symmetric");
//even
}
int halfLength = word.length() / 2;
String firstHalf = word.substring(0, halfLength);
String secondHalf = word.substring(halfLength, word.length());
System.out.println(secondHalf.reverse());
if (firstHalf.equals(secondHalf.reverse()) {
System.out.println("They match");
//they match
}
} }
String does not have a reverse method. You could use the apache commons lang library for this purpose:
http://commons.apache.org/lang/api-release/org/apache/commons/lang3/StringUtils.html#reverse%28java.lang.String%29
The reverse() approach is very clean and readable. Unfortunately there is no reverse() method for Strings. So you would either have to take an external library (StringUtils from the appache common lang3 library has a reverse method) or code it yourself.
public static String reverse(String inputString) {
StringBuilder reverseString = new StringBuilder();
for(int i = inputString.length(); i > 0; --i) {
char result = inputString.charAt(i-1);
reverseString.append(result);
}
return reverseString.toString();
}
(This only works for characters that can fit into a char. So if you need something more general, you would have to expand it.)
Then you can just have a method like this:
enum ePalindromResult { NO_PALINDROM, PALINDROM_ODD, PALINDROM_EVEN };
public static ePalindromResult checkForPalindrom(String inputStr) {
// this uses the org.apache.commons.lang3.StringUtils class:
if (inputStr.equals(StringUtils.reverse(inputStr)) {
if (inputStr.length % 2 == 0) return PALINDROM_EVEN;
else return PALINDROM_ODD;
} else return NO_PALINDROM;
}
System.out.println(secondHalf.reverse());
There is no reverse() method defined fro String
I would probably loop over word from index 0 to the half (word.length() / 2) and compare the character at the current index (word.charAt(i)) with the correspoding from the other half (word.charAt(word.length() - i).
This is just a rough draft, you probably need to think about the loop end index, depending on oddly or evenly symmetry.
You can adapt this :
final char[] word = "abccdccba".toCharArray(); // work also with "abccccba"
final int t = word.length;
boolean ok = true;
for (int i = t / 2; i > 0; i--) {
if (word[i - 1] != word[t - i]) {
ok = false;
break;
}
System.out.println(word[i - 1] + "\t" + word[word.length - i]);
}
System.out.println(ok);
Console :
c c
c c
b b
a a
true
Use class StringBuffer instead of String