(This is not homework)
We have some extra exercices we can do, and i have done some.
But i got stuck in this one...
I need to make a program that given the string "loool" prints "l:1:o:3:l:1".
I have tried a bunch of combinations but i keep getting the same problem:
- I cant make the last repeated letter to get print ( Because with my code the next char needs to be different for a print to occurr).
String str = "loool";
StringBuilder sb = new StringBuilder();
int count = 1;
char before;
before = str.charAt(0);
for (int i = 1;i < str.length();i++) {
if (str.charAt(i) == before) {
count++;
}
else {
sb.append(before + ":" + count);
before = str.charAt(i);
count = 1;
}
}
return sb.toString();
You need to add some logic after your loop has finished, in order to deal with this problem. This logic will probably be very similar to the some of the code that you're using in the else block.
Related
class Solution {
public String reverseWords(String s) {
int count = 0;
int current = 0;
StringBuilder build = new StringBuilder();
for(int i = 0; i< s.length(); i++){
count++;
current = count;
if(s.charAt(i) == ' '){
while(current > 0){
build.append(s.charAt(current - 1));
current--;
}
build.append(s.charAt(i));
}
}
return build.toString();
}
}
I am having trouble understanding why this doesn't work. I went through the
entire code a couple of times but there seems to be an issue.
Input : "Let's take LeetCode contest"
my answer: " s'teL ekat s'teL edoCteeL ekat s'teL "
correct answer: "s'teL ekat edoCteeL tsetnoc"
whats going on?
There are several problems:
You set current to the current position, and then iterate down to 0 append characters. Instead of going down to 0, you iterate until the beginning of the last word. Alternative, iterate until the previous ' ' character.
You only append something after seeing a ' ' character. What will happen at the end of the sentences? As i goes over the letters in the last word, there will be no more ' ' characters, and so the last word will never get appended. To handle this case, you would need to add some logic after the for-loop to check if there is an unwritten word, and append it reversed.
A simpler approach is to take advantage of the StringBuilder's ability to insert characters at some position.
You could track the beginning position of the current word,
and as you iterate over the characters,
insert if it's not ' ',
or else append a ' ' and reset the insertion position.
StringBuilder build = new StringBuilder();
int current = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ' ') {
build.append(' ');
current = i + 1;
} else {
build.insert(current, c);
}
}
return build.toString();
Use a StringBuilder to reverse each word in your String :
String input = "Let's take LeetCode contest";
String[] split = input.split(" +");
StringBuilder output = new StringBuilder();
for (int i = 0; i < split.length; i++) {
output.append(new StringBuilder(split[i]).reverse());
if(i<input.length()-1)
output.append(" ");
}
System.out.println(output);
First, you skip over index 0. Put these lines at the end of your method to avoid this:
count++;
current = count;
You might need a variable to track where the current word began. For example, declare one along with count and current like this:
int wordStart = 0;
Then, when you finish processing a word, set wordStart to point to the first character of the next word. I would put that after the while loop, here:
build.append(s.charAt(i));
wordStart = count + 1;
You will also need to change this: while(current > 0){ to this: while(current >= wordStart)
Also: you don't need count. The variable i is the exact same thing.
You can use stream-api for your goal:
Stream.of(str.split(" "))
.map(s -> new StringBuilder(s).reverse().toString())
.reduce((s1, s2) -> s1 + " " + s2)
.orElse(null);
This is the easy way:
return Arrays.stream(s.split(" " ))
.map(StringBuilder::new)
.map(StringBuilder::reverse)
.map(StringBuilder::toString)
.collect(Collectors.joining(" "));
Code and Error
Error 2
hey Guys see the Image and help me out to sort out this issue
It is the first code and it runs perfectly but when i use the same approach in the blow code it have some error
" For error detail open image link "
String str = "Samaarth";
StringBuilder sb = new StringBuilder(str);
sb.deleteCharAt(3);
System.out.println(sb.toString());
This is where the error start and the error is because of DeleteCharAt() function but in the above code this function works perfectly but here it is not
IDK why so please help me out to sort our this issue
String str= "aaabccddd";
StringBuilder sb = new StringBuilder(str);
for (int i = 0; i < str.length() -1; i++) {
if (sb.charAt(i) == sb.charAt(i + 1)) {
sb.deleteCharAt(i);
//sb.deleteCharAt(i+1);
}
}
System.out.println(sb.toString());
Samarath, you both modify the string and advance the counter.
This is wrong. Consider the string "aaaa"
This is what your code does:
i = 0: you find the duplicate, remove it. The string becomes "aaa".
Then you advance the position: i becomes 1
i = 1: the string is "a|aa" (the vertical bar shows the position).
You find the duplicate at position 1. You kill it, the string
becomes "aa", but you advance the position one again: i becomes 2
At this step the for loop ends and your string is "aa".
Instead the algorithm should use while loop: "while there are duplicates, kill them!"
String str= "aaabccddd";
StringBuilder sb = new StringBuilder(str);
int i = 0;
while (i < sb.length()-1) {
if (sb.charAt(i) == sb.charAt(i + 1)) {
sb.deleteCharAt(i);
// Do not increment -- kill all duplicates
} else {
// Either not a duplicate, or all duplicated killed
// Advance one char
i++;
}
}
System.out.println(sb.toString());
The output is abcd.
If you are inclined to use for loop, then iterate in the reverse order:
String str= "aaabccddd";
StringBuilder sb = new StringBuilder(str);
for (int i = sb.length()-1; i > 0; i--) {
if (sb.charAt(i) == sb.charAt(i - 1)) {
// Note charAt(i - 1) - we compare with the preceding character
sb.deleteCharAt(i);
// The string squeezes by one char, but the decremented position
// will follow
}
}
System.out.println(sb.toString());
The output is abcd
The problem is you are using for loop and you are actually changing/mutating StringBuilder instance at the same time, so the .length() will not be fixed and eventually you will try to reach non-existing index in your for loop and exception will be thrown.
EDIT:
Add these two lines inside your for loop if statement, just before you invoke deleteCharAt() method:
System.out.println("Value of i is: " + i);
System.out.println("StringBuilder length is: " + sb.length());
"i" represents index you are trying to delete, and sb.length() will display actual length of the StringBuilder.
I'm having performance issues. Does anyone have a faster/better solution for doing the following:
String main = "";
for (String proposition : propositions) {
if (main.length() == 0) {
main = proposition;
} else {
main = "|(" + proposition + "," + main + ")";
}
}
I know concat and stringbuilder are faster, but i don't see how i can use these methods. Because of the following line of code:
main = "|(" + proposition + "," + main + ")";
Thanks in advance!
So from what I can tell there are 3 problems here:
Values are primarily prepended to the string.
For each value a character is appended.
If only one value is present, nothing should be appended or prepended.
With 2 or more items, the 0th item is handled differently:
0:""
1:"A"
2:"|(B,A)"
3:"|(C,|(B,A))"
It can be made quicker by making a few changes:
Reverse the algorithm, this means the majority of the work involves appending, allowing you to use StringBuilders.
Count the number of closing )'s and append those after the loop is finished.
Special case for 0 or 1 items in the list.
With those changes the algorithm should be able to use a StringBuilder and be a lot quicker.
Attempt at an algorithm:
int length = propositions.size();
if (length == 0) {
main = "";
} else {
StringBuilder sb = new StringBuilder();
int nestingDepth = 0;
// Reverse loop, ignoring 0th element due to special case
for (int i = length - 1; i > 0; i--) {
sb.append("|(").append(propositions.get(i)).append(',');
nestingDepth++;
}
// Append last element due to special casing
sb.append(propositions.get(0));
for (int i = 0; i < nestingDepth; i++) {
sb.append(')');
}
main = sb.toString();
}
I believe this should produce the correct results, but it should give the right idea.
The problem is that you're prepending and appending to the string as you go. String and StringBuilder dont handle this well (and give quadratic performance). But you can use a dequeue which supports insertion at start and end to store all the pieces. Then finally you can join the bits in the dequeue.
ArrayDeque bits = new ArrayDeque();
for (String proposition : propositions) {
if (bits.size() == 0) {
bits.push(proposition);
} else {
// Add prefix
main.offerFirst("|(" + proposition + "," );
// Add suffix
main.push(")");
}
}
StringBuilder sb = new StringBuilder();
for( String s : bits) {
sb.append(s);
}
main = sb.toString();
Assuming this is an array of propositions, you could first sum the length of the String(s) in the array. Add 4 for your additional characters, and subtract 4 because you don't use those separators on the first element. That should be the perfect size for your output (this is optional, because StringBuilder is dynamically sized). Next, construct a StringBuilder. Add the first element. All subsequent elements follow the same pattern, so the loop is simplified with a traditional for. Something like,
int len = Stream.of(propositions).mapToInt(s -> s.length() + 4).sum() - 4;
StringBuilder sb = new StringBuilder(len); // <-- len is optional
sb.append(propositions[0]);
for (int i = 1; i < propositions.length; i++) {
sb.insert(0, ",").insert(0, propositions[i]).insert(0, "|(").append(")");
}
System.out.println(sb);
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
How can I break a line automatically into many lines without cutting off words? And the length for each new line will be around 4 words? I have many sentences thus I cannot use \n
e.g:
If I were you I would go to the cinema with her
becomes:
If I were you
I would go to
the cinema with her
Hope see your help soon. Thanks!
I would imagine, based on what you put although I'm not sure you're considering all possible cases, a way to get the specific answer you're looking for while taking a few things for granted and not directly relying on "\n" would be...
String s = "If I were you I would go to the cinema with her";
String[] strings = s.split(" ");
for(int i = 0; i < strings.length; ++i) {
if(i % 4 == 0) {
System.out.println();
}
System.out.print(strings[i] + " ");
}
Alternatively you might consider something like this, which would handle a max width of your text field as opposed to a set number of words since some words may be very long and cause a situation which you're trying to avoid...
int MAX = 20;
int length = 0;
String s = "If I were you I would go to the cinema with her.";
String[] strings = s.split(" ");
for(int i = 0; i < strings.length; ++i) {
if((length + strings[i].length()) > MAX ) {
System.out.println();
length = 0;
}
System.out.print(strings[i] + " ");
length += strings[i].length() + 1;
}
Edit:
I did as you requested. This is what I get from the MAX option...
If I were you I
would go to the
cinema with her and
abc xyz
And this is what I get for the regular...
If I were you
I would go to
the cinema with her
and abc xyz
Not sure what's happening there, but I will say I jumped the shark on my answer. You've tagged Android and you and I both know System.out.println() is a no-no in that environment, at least if you expect to see any results. Sorry about that.
you need to count the number of spaces in a for loop here is a code to demonstrate it. please change the variables according to your application
String tv2 = tv.getText().toString(); // take a string textVIew, you can make it editView
StringBuilder sb = new StringBuilder(tv2); // add the string to stringBuilder
int howManySpaces = 0; // this for counting the spaces.
for (int i = 0; i < tv2.length(); i++)
{
if (tv2.charAt(i) == ' ') //if space found add one to howManySpaces
{
howManySpaces += 1;
Log.d("HMS", String.valueOf(howManySpaces));
}
if (howManySpaces == 4) // if howManySpaces == 4 break it to new line
{
sb.replace(i, i+1, "\n");
howManySpaces = 0;
}
}
tvNew.setText(sb.toString()); // add to the new textView the result after breaking.
I just tried it right now, with same sentences it gave me the desired result.
feel free to ask me if you didnt understand any part.
I have tried the following code, it worked fine for me, please try this and kindly let me if you have any trouble on this
// Calling the SentenceBreaker method which helps the String to split.
sentenceBreaker("If I were you I would go to the cinema with her");
// Method which spilts the Sentence
private void sentenceBreaker(int noOfWords,String inputSentence){
boolean previousCharWhiteSpace = true; // just a flag
boolean initialFlag =false;
int wordCount = 0;
int i,count =0;
for (i = 0; i < inputSentence.length(); i++) {
if (inputSentence.charAt(i) == ' ' && !previousCharWhiteSpace) {
wordCount++;
previousCharWhiteSpace = true;
if (wordCount == noOfWords) {
if(count == 0){
inputSentence = inputSentence.substring(0,wordCount)
+ "\n"
+ inputSentence.substring(wordCount,
inputSentence.length());
wordCount = 0;
count=i;
}
else{
inputSentence = inputSentence.substring(count, i)
+ "\n"
+ inputSentence.substring(i,
inputSentence.length());
wordCount = 0;
count=i;
}
}
} else if (!(inputSentence.charAt(i) == ' ')) {
previousCharWhiteSpace = false;
}
}
/*
* the for loop increments the word count if a space is encountered
* between words,for multiple spaces between words it wont update the
* counter-hence the use of the boolean flag.
*/
if (!(inputSentence.charAt(i - 1) == ' ')) {
wordCount++;
}
// just to make sure that we count the last word in the sentence as well
System.out.println("No of words-" + wordCount);
System.out.println("Sentence" + inputSentence);
}
/* Output */
Sentence If I were you
I would go to
the cinema with her**
As Per Your Requirement..Following logic will be works fine..Please Use it
String stT="If I were you I would go to the cinema with her";
String[] sT=stT.split(" ");
StringBuffer sb=new StringBuffer();
for(int i=0;i<sT.length;i++)
{
if(i%4==3)
sb.append(sT[i]+"\n");
else
sb.append(sT[i]+" ");
}
System.out.print(sb.toString());
Thanks in advance.
I just solved Project Euler #22, a problem involving reading about 5,000 lines of text out of a file and determining the value of a specific name, based on the sum of that Strings characters, and its position alphabetically.
However, the code takes about 5-10 seconds to run, which is a bit annoying. What is the best way to optimize this code? I'm currently using a Scanner to read the file into a String. Is there another, more efficient way to do this? (I tried using a BufferedReader, but that was even slower)
public static int P22(){
String s = null;
try{
//create a new Scanner to read file
Scanner in = new Scanner(new File("names.txt"));
while(in.hasNext()){
//add the next line to the string
s+=in.next();
}
}catch(Exception e){
}
//this just filters out the quotation marks surrounding all the names
String r = "";
for(int i = 0;i<s.length();i++){
if(s.charAt(i) != '"'){
r += s.charAt(i);
}
}
//splits the string into an array, using the commas separating each name
String text[] = r.split(",");
Arrays.sort(text);
int solution = 0;
//go through each string in the array, summing its characters
for(int i = 0;i<text.length;i++){
int sum = 0;
String name = text[i];
for(int j = 0;j<name.length();j++){
sum += (int)name.charAt(j)-64;
}
solution += sum*(i+1);
}
return solution;
}
If you're going to use Scanner, why not use it for what it's supposed to do (tokenisation)?
Scanner in = new Scanner(new File("names.txt")).useDelimiter("[\",]+");
ArrayList<String> text = new ArrayList<String>();
while (in.hasNext()) {
text.add(in.next());
}
Collections.sort(text);
You do not need to strip quotes, or split on commas - Scanner does it all for you.
This snippet, including java startup time, executes in 0.625s (user time) on my machine. I suspect it should be a bit faster than what you were doing.
EDIT OP asked what the string passed to useDelimiter was. It's a regular expression. When you strip out the escaping required by Java to include a quote character into a string, it's [",]+ - and the meaning is:
[...] character class: match any of these characters, so
[",] match a quote or a comma
...+ one or more occurence modifier, so
[",]+ match one or more of quotes or commas
Sequences that would match this pattern include:
"
,
,,,,
""",,,",","
and indeed ",", what was what we were going after here.
I suggest you to run your code with profiler. It allows you to understand, what part is really slow (IO/computations etc). If IO is slow, check for NIO: http://docs.oracle.com/javase/1.4.2/docs/guide/nio/.
Appending strings in a loop with '+', like you do here:
/* That's actually not the problem since there is only one line. */
while(in.hasNext()){
//add the next line to the string
s+=in.next();
}
is slow, because it has to create a new string and copy everything around in each iteration. Try using a StringBuilder,
StringBuilder sb = new StringBuilder();
while(in.hasNext()){
sb.append(in.next());
}
s = sb.toString();
But, you shouldn't really read the file contents into a String, you should create a String[] or an ArrayList<String> from the file contents directly,
int names = 5000; // use the correct number of lines in the file!
String[] sa = new String[names];
for(int i = 0; i < names; ++i){
sa[i] = in.next();
}
However, upon checking, it turns out that the file does not contain about 5000 lines, rather, it is all on a single line, so your big problem is actually
/* This one is the problem! */
String r = "";
for(int i = 0;i<s.length();i++){
if(s.charAt(i) != '"'){
r += s.charAt(i);
}
}
Use a StringBuilder for that. Or, make your Scanner read until the next ',' and read directly into an ArrayList<String> and just remove the double quotes from each single name in the ArrayList.
5+ seconds is quite slow for this problem. My entire web application (600 Java classes) compiles in four seconds. The root of your problem is probably the allocation of a new String for every character in the file: r += s.charAt(i)
To really speed this up, you should not use Strings at all. Get the file size, and read the whole thing into a byte array in a single I/O call:
public class Names {
private byte[] data;
private class Name implements Comparable<Name> {
private int start; // index into data
private int length;
public Name(int start, int length) { ...; }
public int compareTo(Name arg0) {
...
}
public int score()
}
public Names(File file) throws Exception {
data = new byte[(int) file.length()];
new FileInputStream(file).read(data, 0, data.length);
}
public int score() {
SortedSet<Name> names = new ...
for (int i = 0; i < data.length; ++i) {
// find limits of each name, add to the set
}
// Calculate total score...
}
}
Depending on the application, StreamTokenizer is often measurably faster than Scanner. Examples comparing the two may be found here and here.
Addendum: Euler Project 22 includes deriving a kind of checksum of the characters in each token encountered. Rather than traversing the token twice, a custom analyzer could combine the recognition and calculation. The result would be stored in a SortedMap<String, Integer> for later iteration in finding the grand total.
An obtuse solution which may find interesting.
long start = System.nanoTime();
long sum = 0;
int runs = 10000;
for (int r = 0; r < runs; r++) {
FileChannel channel = new FileInputStream("names.txt").getChannel();
ByteBuffer bb = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
TLongArrayList values = new TLongArrayList();
long wordId = 0;
int shift = 63;
while (true) {
int b = bb.remaining() < 1 ? ',' : bb.get();
if (b == ',') {
values.add(wordId);
wordId = 0;
shift = 63;
if (bb.remaining() < 1) break;
} else if (b >= 'A' && b <= 'Z') {
shift -= 5;
long n = b - 'A' + 1;
wordId = (wordId | (n << shift)) + n;
} else if (b != '"') {
throw new AssertionError("Unexpected ch '" + (char) b + "'");
}
}
values.sort();
sum = 0;
for (int i = 0; i < values.size(); i++) {
long wordSum = values.get(i) & ((1 << 8) - 1);
sum += (i + 1) * wordSum;
}
}
long time = System.nanoTime() - start;
System.out.printf("%d took %.3f ms%n", sum, time / 1e6);
prints
XXXXXXX took 27.817 ms.