I am working on a DP problem in which a string of words with space removed, and I need to implement both buttom-up and memoization version to split the string into individual english words. However, I got the buttom-up version, however, the memoization seems a little complicated.
/* Split a string into individual english words
* #String str the str to be splitted
* #Return a sequence of words separated by space if successful,
null otherwise
*/
public static String buttom_up_split(String str){
int len = str.length();
int[] S = new int[len+1];
/*Stores all the valid strings*/
String[] result = new String[len+1];
/*Initialize the array*/
for(int i=0; i <= len; i++){
S[i] = -1;
}
S[0] =0;
for(int i=0; i < len; i++){
if(S[i] != -1){
for(int j= i+1; j <= len; j++){
String sub = str.substring(i, j);
int k = j;
if(isValidEnglishWord(sub)){
S[k] = 1; //set true indicates a valid split
/*Add space between words*/
if(result[i] != null){
/*Add the substring to the existing words*/
result[i+ sub.length()] = result[i] + " " + sub;
}
else{
/*The first word*/
result[i+ sub.length()] = sub;
}
}
}
}
}
return result[len]; //return the last element of the array
}
I really confused how to convert this buttom_up_version to the memoized version, hope someone can help..
Well, I'm not an export of memoization, but the idea is to have a "memory" of previous good english words.
The objective is to save computation time: in your case, the call to isValidEnglishWord().
Therefore, you need to adapt your alorythm this way:
walk through the 'str' string
extract a substring from it
checkif the substring is a valid word in your memory.
It's in memory: add a space and the word to your result.
It's not in memory: calls isValidEnglishWord and process its return.
It will give something like (not tested nor compiled)
// This is our memory
import java.util.*
private static Map<String, Boolean> memory = new HashMap<String, Boolean>()
public static String buttom_up_split(String str){
int len = str.length();
int[] S = new int[len+1];
String[] result = new String[len+1];
for(int i=0; i <= len; i++){
S[i] = -1;
}
S[0] =0;
for(int i=0; i < len; i++){
if(S[i] != -1){
for(int j= i+1; j <= len; j++){
String sub = str.substring(i, j);
int k = j;
// Order is significant: first look into memory !
Boolean isInMemory = memory.contains(sub);
if (isInMemory || isValidEnglishWord(sub)){
S[k] = 1;
if(result[i] != null){
// Memoize the result if needed.
if (!isInMemory) {
memory.put(sub, true);
}
result[i+ sub.length()] = result[i] + " " + sub;
} else {
result[i+ sub.length()] = sub;
}
}
}
}
}
return result[len];
}
Personally I always prefer to use memoization as transparently as possible without modifying the algorithm. This is because I want to be able to test the algorithm separately from memoization. Also I am working on a memoization library in which you only have to add #Memoize to methods to which memoization is applicable. But unfortunately this will come too late for you.
The last time I used memoization (without my library) I implemented it using a proxy class. An important remark is that this implementation does not support recursion. But this shouldn't be a problem since your algorithm is not recursive.
Some other references are:
wikipedia
Java implementation
memoize using proxy class
Remark about your algorithm:
How do you handle words that have other words in them? like "verbose" contains "verb", "theory" contains "the" etc...
Related
Hello I am having trouble implementing this function
Function:
Decompress the String s. Character in the string is preceded by a number. The number tells you how many times to repeat the letter. return a new string.
"3d1v0m" becomes "dddv"
I realize my code is incorrect thus far. I am unsure on how to fix it.
My code thus far is :
int start = 0;
for(int j = 0; j < s.length(); j++){
if (s.isDigit(charAt(s.indexOf(j)) == true){
Integer.parseInt(s.substring(0, s.index(j))
Assuming the input is in correct format, the following can be a simple code using for loop. Of course this is not a stylish code and you may write more concise and functional style code using Commons Lang or Guava.
StringBuilder builder = new StringBuilder();
for (int i = 0; i < s.length(); i += 2) {
final int n = Character.getNumericValue(s.charAt(i));
for (int j = 0; j < n; j++) {
builder.append(s.charAt(i + 1));
}
}
System.out.println(builder.toString());
Here is a solution you may like to use that uses Regex:
String query = "3d1v0m";
StringBuilder result = new StringBuilder();
String[] digitsA = query.split("\\D+");
String[] letterA = query.split("[0-9]+");
for (int arrIndex = 0; arrIndex < digitsA.length; arrIndex++)
{
for (int count = 0; count < Integer.parseInt(digitsA[arrIndex]); count++)
{
result.append(letterA[arrIndex + 1]);
}
}
System.out.println(result);
Output
dddv
This solution is scalable to support more than 1 digit numbers and more than 1 letter patterns.
i.e.
Input
3vs1a10m
Output
vsvsvsammmmmmmmmm
Though Nami's answer is terse and good. I'm still adding my solution for variety, built as a static method, which does not use a nested For loop, instead, it uses a While loop. And, it requires that the input string has even number of characters and every odd positioned character in the compressed string is a number.
public static String decompress_string(String compressed_string)
{
String decompressed_string = "";
for(int i=0; i<compressed_string.length(); i = i+2) //Skip by 2 characters in the compressed string
{
if(compressed_string.substring(i, i+1).matches("\\d")) //Check for a number at odd positions
{
int reps = Integer.parseInt(compressed_string.substring(i, i+1)); //Take the first number
String character = compressed_string.substring(i+1, i+2); //Take the next character in sequence
int count = 1;
while(count<=reps)//check if at least one repetition is required
{
decompressed_string = decompressed_string + character; //append the character to end of string
count++;
};
}
else
{
//In case the first character of the code pair is not a number
//Or when the string has uneven number of characters
return("Incorrect compressed string!!");
}
}
return decompressed_string;
}
I'm taking care of some other methods and I don't know what to do with this one. I want to change the order of the string inside the array (not the order of the string*s*), but this isn't accepted. Any ideas?
public void invert() {
for(int i = 0; i < array.length; i++){
for(int j = 0, k = array[i].length() - 1; j < k; j++, k--){
char a = array[i].charAt(j);
array[i].charAt(j) = array[k].charAt(k); //ERROR HERE
array[i].charAt(k) = a; //AND HERE
}
}
}
EDIT: I'll leave here what I mean.
I have an array = {"Hello", "Goodbye"}
I want to change it to {"olleH", "eybdooG"}
Java string are immutable. You can't change them.
(But you can convert the string to a StringBuilder - http://docs.oracle.com/javase/tutorial/java/data/buffers.html - which is essentialy a mutable string, change the characters, and then convert the StrignBuilder back to String.)
Try this code (I haven't tested it, but I hope it works):
for(int i = 0; i < array.length; i++) {
StringBuilder b = new StringBuilder(array[i]);
for(int j = 0, k = b.length() - 1; j < k; j++, k--){
char a = b.charAt(j);
b.setCharAt(j, array[k].charAt(k));
b.setCharAt(k, a);
}
array[i] = b.toString();
}
array[i].charAt(j) = array[k].charAt(k); //ERROR HERE
array[i].charAt(a) returns a value not a variable. You are trying to assign a value to a value which doesn't make any sense.
java String is immutable. You can't change it.
Use StringBuilder which has setCharAt(int index,
char ch); function which is what you are probably wanting.
The most simple way is, to reverse letter with StringBuilder.reverse() method. Try,
for(String str : array){
System.out.println(new StringBuilder(str).reverse());
}
Just use this on every String in your array:
String reversed = new StringBuilder(stringFromArray).reverse().toString();
try doing new StringBuilder(array[i]).reverse().toString();
you would have to create a substring.
array[i]= array[i].substring(0,j) + array[k].charAt(k) + array[i].substring(j+1);
This would do the required edit i beleive
I'm doing a project for Java 1, and I'm completely stuck on this question.
Basically I need to double each letter in a string.
"abc" -> "aabbcc"
"uk" -> "uukk"
"t" -> "tt"
I need to do it in a while loop in what is considered "Java 1" worthy. So i'm guessing that this means more of a problematic approach.
I know that the easiest way for me to do this, from my knowledge, would be using the charAt method in a while loop, but for some reason my mind can't figure out how to return the characters to another method as a string.
Thanks
[EDIT] My Code (wrong, but maybe this will help)
int index = 0;
int length = str.length();
while (index < length) {
return str.charAt(index) + str.charAt(index);
index++;
}
String s="mystring".replaceAll(".", "$0$0");
The method String.replaceAll uses the regular expression syntax which is described in the documentation of the Pattern class, where we can learn that . matches “any character”. Within the replacement, $number refers to numbered “capturing group” whereas $0 is predefined as the entire match. So $0$0 refers to the matching character two times. As the name of the method suggests, it is performed for all matches, i.e. all characters.
Yeah, a for loop would really make more sense here, but if you need to use a while loop then it would look like this:
String s = "abc";
String result = "";
int i = 0;
while (i < s.length()){
char c = s.charAt(i);
result = result + c + c;
i++;
}
You can do:
public void doubleString(String input) {
String output = "";
for (char c : input.toCharArray()) {
output += c + c;
}
System.out.println(output);
}
Your intuition is very good. charAt(i) will return the character in the string at location i, yes?
You also said you wanted to use a loop. A for loop, traversing the length of the list, string.length(), will allow you to do this. At every single node in the string, what do you need to do? Double the character.
Let's take a look at your code:
int index = 0;
int length = str.length();
while (index < length) {
return str.charAt(index) + str.charAt(index); //return ends the method
index++;
}
Problematically for your code, you are returning two characters immediately upon entering the loop. So for a string abc, you are returning aa. Let's store the aa in memory instead, and then return the completed string like so:
int index = 0;
int length = str.length();
String newString = "";
while (index < length) {
newString += str.charAt(index) + str.charAt(index);
index++;
}
return newString;
This will add the character to newString, allowing you to return the entire completed string, as opposed to a single set of doubled characters.
By the way, this may be easier to do as a for loop, condensing and clarifying your code. My personal solution (for a Java 1 class) would look something like this:
String newString = "";
for (int i = 0; i < str.length(); i++){
newString += str.charAt(i) + str.charAt(i);
}
return newString;
Hope this helps.
try this
String a = "abcd";
char[] aa = new char[a.length() * 2];
for(int i = 0, j = 0; j< a.length(); i+=2, j++){
aa[i] = a.charAt(j);
aa[i+1]= a.charAt(j);
}
System.out.println(aa);
public static char[] doubleChars(final char[] input) {
final char[] output = new char[input.length * 2];
for (int i = 0; i < input.length; i++) {
output[i] = input[i];
output[i + 1] = input[i];
}
return output;
}
Assuming this is inside a method, you should understand that you can only return once from a method. After encountering a return statement, the control goes back to the calling method. Thus your approach of returning char every time in a loop is faulty.
int index = 0;
int length = str.length();
while (index < length) {
return str.charAt(index) + str.charAt(index); // only the first return is reachable,other are not executed
index++;
}
Change your method to build a String and return it
public String modify(String str)
{
int index = 0;
int length = str.length();
String result="";
while (index < length) {
result += str.charAt[index]+str.charAt[index];
index++;
}
return result;
}
I'm having trouble with this, maybe you could help me:
I have 3 strings like: word1, word2, word3 and I have to build a matrix with them, like this:
on the first row : word1("ABC"), second row: word2("DEF") and third row: word3("GHI").
A|B|C
D|E|F
G|H|I
I need this because after that I have to check if the formed words ("ADG","BEH","CFI") are in an array of words. And I don't know how to put those strings in the matrix so I can check. Any help is useful.
Thanks
Based on this comment:
the words have the same size, because the matrix is actually like a puzzle. I choose randomly 3 words from an array, put them in a matrix and check after that if the words resulted are from the same array.
I'll assume some things in order to make this work (since we don't have enough info):
You have an array of Strings where you have all the words
private String[] words;
You have a method to randomly pick up 3 Strings from this array.
private String s1, s2, s3;
public void pickThreeRandomWords() {
s1 = aRandomWord(words);
s2 = aRandomWord(words);
s3 = aRandomWord(words);
//or maybe another fancy algorithm to get this...
}
So you would need an array of array of chars based on these 3 Strings. This code could do the work for you:
public char[][] createMatrixFromStrings(String s1, String s2, String s3) {
char[][] theMatrix = new char[3][]; //yes, hardcoded
theMatrix[0] = s1.toCharArray();
theMatrix[1] = s2.toCharArray();
theMatrix[2] = s3.toCharArray();
return theMatrix;
}
Of course, if you would want to make this method to support more than 3 Strings you can make the method to receive a random quantity of Strings:
public char[][] createMatrixFromStrings(String ... strings) {
if (strings == null || strings.length == 0) return null;
char[][] theMatrix = new char[strings.length][];
int i = 0;
for(String s : strings) {
theMatrix[i++] = s.toCharArray();
}
return theMatrix;
}
You can build the result words without a matrix:
List<String> verticalWords = new ArrayList<String>();
for (int i = 0; i < horizontalLen; i++){
String currentWord = "";
for (int j = 0; j < wordCount; j++)
currentWord += words.get(j).get(i);
verticalWords.add(currentWord);
}
P.S. For the currentWord you can use a StringBuilder to make it more efficient, but I doubt it is highly needed here.
Java doesn't have matrix.It has array of array
So,you can try this
List<char[]> lst=new ArrayList();//stores a list of char[]
lst.add(("ADC".toCharArray()));//adds array of characters i.e 'A','D','C'
lst.add(("DEF".toCharArray()));
lst.get(0)[0];//A
lst.get(1)[0];//D
Now you can iterate vertically
for(int i=0;i<lst.size();i++)temp+=lst.get(i)[0];
temp would have AD which you can now cross check with equals method
The main thrust of this goal is that you're taking a one-dimensional value, and converting it into a two-dimensional value. There are many ways you can do this, but here are the two that come off the top of my head:
Set up a nested while loop to iterate over the first dimension, and when it reaches the length, reset and cause the outer loop to increment, much like a clock
You can create a new subarray using ArrayUtils.toSubArray(), and with some finagling, get that to work:
Create a new row of the array each time, based on the dimension slices you want to hit up. I'll leave figuring this one out as an exercise for the reader. But here's a hint:
for(int i = 0; i < theDimension; i++, j += 3) {
ret[i] = ArrayUtils.subarray(word, i*theDimension, j);
}
Lastly, I assume that there's a restraint on the type of input you can receive. The matrix must be square, so I enforce that restriction before we build the array.
I strongly encourage you to poke and prod this answer, and not just blindly copy it into your schoolwork. Understand what it's doing so you can reproduce it when you're asked to again in the future.
public char[][] toMatrix(int theDimension, String theEntireWord) {
if(theEntireWord.length() != theDimension * theDimension) {
throw new IllegalArgumentException("impossible to add string to matrix of uneven dimension");
}
char[][] ret = new char[theDimension][theDimension];
int i = 0;
int j = 0;
while(i < theDimension) {
if(j == theDimension) {
j = 0;
++i;
} else {
ret[i][j] = theEntireWord.charAt((i * theDimension) + j);
j++;
}
}
return ret;
}
I think this will sort your problem.
package printing;
public class Matrix {
public static void main(String[] args) {
//Length can define as you wish
String[] max = new String[10];
String[] out = null;
//Your Inputs
max[0]="ADG";
max[1]="BEH";
max[2]="CFI";
//following for loop iterate your inputs
for (int i = 0; i < max.length; i++) {
if(out==null){out= new String[max.length];}
String string = max[i];
if(string==null){ break;}
//Here breaking input(words) one by one into letters for later contcatnating.
String[] row = string.split("");
for (int j = 0; j < row.length; j++) {
String string1 = row[j];
// System.out.println(string1);
//create the values for rows
if(out[j]!=null){ out[j]=out[j]+string1;}
else{
out[j]=string1;
}
}
}
//following for loop will out put your matrix.
for (int i = 0; i < out.length; i++) {
String string = out[i];
if(out[i]==null){break;}
System.out.println(out[i]);
}
}
}
Suppose some situations exist where you would like to increment and decrement values in the same for loop. In this set of situations, there are some cases where you can "cheat" this by taking advantage of the nature of the situation -- for example, reversing a string.
Because of the nature of building strings, we don't really have to manipulate the iterate or add an additional counter:
public static void stringReversal(){
String str = "Banana";
String forwardStr = new String();
String backwardStr = new String();
for(int i = str.length()-1; i >= 0; i--){
forwardStr = str.charAt(i)+forwardStr;
backwardStr = backwardStr+str.charAt(i);
}
System.out.println("Forward String: "+forwardStr);
System.out.println("Backward String: "+backwardStr);
}
However, suppose a different case exists where we just want to print a decremented value, from the initial value to 0, and an incremented value, from 0 to the initial value.
public static void incrementAndDecrement(){
int counter = 0;
for(int i = 10; i >= 0; i--){
System.out.println(i);
System.out.println(counter);
counter++;
}
}
This works well enough, but having to create a second counter to increment seems messy. Are there any mathematical tricks or tricks involving the for loop that could be used that would make counter redundant?
Well it looks like you just want:
for(int i = 10; i >= 0; i--){
System.out.println(i);
System.out.println(10 - i);
}
Is that the case? Personally I'd normally write this as an increasing loop, as I find it easier to think about that:
for (int i = 0; i <= 10; i++) {
System.out.println(10 - i);
System.out.println(i);
}
Note that your string example is really inefficient, by the way - far more so than introducing an extra variable. Given that you know the lengths involved to start with, you can just start with two char[] of the right size, and populate the right index each time. Then create a string from each afterwards. Again, I'd do this with an increasing loop:
char[] forwardChars = new char[str.length()];
char[] reverseChars = new char[str.length()];
for (int i = 0; i < str.length(); i++) {
forwardChars[i] = str.charAt(i);
reverseChars[reverseChars.length - i - 1] = str.charAt(i);
}
String forwardString = new String(forwardChars);
String reverseString = new String(reverseChars);
(Of course forwardString will just be equal to str in this case anyway...)
You can have multiple variables and incrementers in a for loop.
for(int i = 10, j = 0; i >= 0; i--, j++) {
System.out.println(i);
System.out.println(j);
}