I fail to understand the rules of using StringBuffer, append, conversions - java

I was wondering if anyone could help me figuring out why my code doesn't do what I expect it to do. The idea was to count the same following letters in a StringBuffer and transform it into something like this AABBC => 2A2B1C. Now my program doesn't do that and it probably has to do with my poor usage of these newly-learned concepts. Do I have to convert marker into a char for it to print it out? Or is the structure of my code inherently wrong? I'm also not sure what I can do with StringBuffers and what not.
package package1;
public class Strings {
public static void main(String[]args){
int marker = 1;
StringBuffer s2 = new StringBuffer();
StringBuffer s = new StringBuffer("AAAA");
for(int i = 0; i<=s.length(); i++){
while(s.charAt(i) == s.charAt(i+1)){
marker++;
}
i += marker;
s2.append(marker);
s2.append(s.charAt(i));
marker = 0;
}
System.out.println(s2); // It simply prints out nothing
}
}

You have an off-by-one-error bug in your code.
You are counting how many times you've seen a char starting from 1 but string indexes start from zero and you are mixing up the two later when you are assigning marker to i using getCharAt(i) is off by one (in this case it tries to get the char at index 4 which is passed the end of the string).
An Easy way to fix it is to have your count (marker) start at 0 too and only increase by one what you are appending to the string:
package package1;
public class Strings {
public static void main(String[]args){
int marker = 0; // changing this to 0
StringBuffer s2 = new StringBuffer();
StringBuffer s = new StringBuffer("AAAA");
for(int i = 0; i<=s.length(); i++){
while(s.charAt(i) == s.charAt(i+1)){
marker++;
}
i += marker;
s2.append(marker + 1); // print out the count plus one because we are counting from zero
s2.append(s.charAt(i));
marker = 0;
}
System.out.println(s2); // It simply prints out nothing
}
}

Your while-loop never finishes.
If s.charAt(i) == s.charAt(i+1) is true, the marker gets increased. But because i stays the same the condition of your while-loop stays the same, so it runs for ever.
There are some more bugs in your code (like i <= s.length() and try to access s.charAt(i+1) will lead to IndexOutOfBoundsException) but you will find them.

Related

how to compare two strings to find common substring

i get termination due to timeout error when i compile. Please help me
Given two strings, determine if they share a common substring. A substring may be as small as one character.
For example, the words "a", "and", "art" share the common substring "a" . The words "be" and "cat" do not share a substring.
Input Format
The first line contains a single integer , the number of test cases.
The following pairs of lines are as follows:
The first line contains string s1 .
The second line contains string s2 .
Output Format
For each pair of strings, return YES or NO.
my code in java
public static void main(String args[])
{
String s1,s2;
int n;
Scanner s= new Scanner(System.in);
n=s.nextInt();
while(n>0)
{
int flag = 0;
s1=s.next();
s2=s.next();
for(int i=0;i<s1.length();i++)
{
for(int j=i;j<s2.length();j++)
{
if(s1.charAt(i)==s2.charAt(j))
{
flag=1;
}
}
}
if(flag==1)
{
System.out.println("YES");
}
else
{
System.out.println("NO");
}
n--;
}
}
}
any tips?
Below is my approach to get through the same HackerRank challenge described above
static String twoStrings(String s1, String s2) {
String result="NO";
Set<Character> set1 = new HashSet<Character>();
for (char s : s1.toCharArray()){
set1.add(s);
}
for(int i=0;i<s2.length();i++){
if(set1.contains(s2.charAt(i))){
result = "YES";
break;
}
}
return result;
}
It passed all the Test cases without a time out issue.
The reason for the timeout is probably: to compare two strings that each are 1.000.000 characters long, your code needs 1.000.000 * 1.000.000 comparisons, always.
There is a faster algorithm that only needs 2 * 1.000.000 comparisons. You should use the faster algorithm instead. Its basic idea is:
for each character in s1: add the character to a set (this is the first million)
for each character in s2: test whether the set from step 1 contains the character, and if so, return "yes" immediately (this is the second million)
Java already provides a BitSet data type that does all you need. It is used like this:
BitSet seenInS1 = new BitSet();
seenInS1.set('x');
seenInS1.get('x');
Since you're worried about execution time, if they give you an expected range of characters (for example 'a' to 'z'), you can solve it very efficiently like this:
import java.util.Arrays;
import java.util.Scanner;
public class Whatever {
final static char HIGHEST_CHAR = 'z'; // Use Character.MAX_VALUE if unsure.
public static void main(final String[] args) {
final Scanner scanner = new Scanner(System.in);
final boolean[] characterSeen = new boolean[HIGHEST_CHAR + 1];
mainloop:
for (int word = Integer.parseInt(scanner.nextLine()); word > 0; word--) {
Arrays.fill(characterSeen, false);
final String word1 = scanner.nextLine();
for (int i = 0; i < word1.length(); i++) {
characterSeen[word1.charAt(i)] = true;
}
final String word2 = scanner.nextLine();
for (int i = 0; i < word2.length(); i++) {
if (characterSeen[word2.charAt(i)]) {
System.out.println("YES");
continue mainloop;
}
}
System.out.println("NO");
}
}
}
The code was tested to work with a few inputs.
This uses a fast array rather than slower sets, and it only creates one non-String object (other than the Scanner) for the entire run of the program. It also runs in O(n) time rather than O(n²) time.
The only thing faster than an array might be the BitSet Roland Illig mentioned.
If you wanted to go completely overboard, you could also potentially speed it up by:
skipping the creation of a Scanner and all those String objects by using System.in.read(buffer) directly with a reusable byte[] buffer
skipping the standard process of having to spend time checking for and properly handling negative numbers and invalid inputs on the first line by making your own very fast int parser that just assumes it's getting the digits of a valid nonnegative int followed by a newline
There are different approaches to solve this problem but solving this problem in linear time is a bit tricky.
Still, this problem can be solved in linear time. Just apply KMP algorithm in a trickier way.
Let's say you have 2 strings. Find the length of both strings first. Say length of string 1 is bigger than string 2. Make string 1 as your text and string 2 as your pattern. If the length of the string is n and length of the pattern is m then time complexity of the above problem would be O(m+n) which is way faster than O(n^2).
In this problem, you need to modify the KMP algorithm to get the desired result.
Just need to modify the KMP
public static void KMPsearch(char[] text,char[] pattern)
{
int[] cache = buildPrefix(pattern);
int i=0,j=0;
while(i<text.length && j<pattern.length)
{
if(text[i]==pattern[j])
{System.out.println("Yes");
return;}
else{
if(j>0)
j = cache[j-1];
else
i++;
}
}
System.out.println("No");
return;
}
Understanding Knuth-Morris-Pratt Algorithm
There are two concepts involved in solving this question.
-Understanding that a single character is a valid substring.
-Deducing that we only need to know that the two strings have a common substring — we don’t need to know what that substring is.
Thus, the key to solving this question is determining whether or not the two strings share a common character.
To do this, we create two sets, a and b, where each set contains the unique characters that appear in the string it’s named after.
Because sets 26 don’t store duplicate values, we know that the size of our sets will never exceed the letters of the English alphabet.
In addition, the small size of these sets makes finding the intersection very quick.
If the intersection of the two sets is empty, we print NO on a new line; if the intersection of the two sets is not empty, then we know that strings and share one or more common characters and we print YES on a new line.
In code, it may look something like this
import java.util.*;
public class Solution {
static Set<Character> a;
static Set<Character> b;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
for(int i = 0; i < n; i++) {
a = new HashSet<Character>();
b = new HashSet<Character>();
for(char c : scan.next().toCharArray()) {
a.add(c);
}
for(char c : scan.next().toCharArray()) {
b.add(c);
}
// store the set intersection in set 'a'
a.retainAll(b);
System.out.println( (a.isEmpty()) ? "NO" : "YES" );
}
scan.close();
}
}
public String twoStrings(String sOne, String sTwo) {
if (sOne.equals(sTwo)) {
return "YES";
}
Set<Character> charSetOne = new HashSet<Character>();
for (Character c : sOne.toCharArray())
charSetOne.add(c);
Set<Character> charSetTwo = new HashSet<Character>();
for (Character c : sTwo.toCharArray())
charSetTwo.add(c);
charSetOne.retainAll(charSetTwo);
if (charSetOne.size() > 0) {
return "YES";
}
return "NO";
}
This must work. Tested with some large inputs.
Python3
def twoStrings(s1, s2):
flag = False
for x in s1:
if x in s2:
flag = True
if flag == True:
return "YES"
else:
return "NO"
if __name__ == '__main__':
q = 2
text = [("hello","world"), ("hi","world")]
for q_itr in range(q):
s1 = text[q_itr][0]
s2 = text[q_itr][1]
result = twoStrings(s1, s2)
print(result)
static String twoStrings(String s1, String s2) {
for (Character ch : s1.toCharArray()) {
if (s2.indexOf(ch) > -1)
return "YES";
}
return "NO";
}

Reduced String - compress

I am practicing Strings programming examples. i would like to reduce the given strings. it should eliminate a character if its in even numbers
example: Input - aaabbc, Output should be: ac
I have used HashMap to count and store character and count value and computing using value % 2 then continue or else print the output. But some of the test cases are failing in Hackerrank. Could you please help me identify the problem?
static String super_reduced_string(String s){
HashMap<Character, Integer> charCount = new HashMap<Character, Integer>();
StringBuilder output = new StringBuilder();
if (s == null || s.isEmpty()) {
return "Empty String";
}
char[] arr = s.toCharArray();
for (int i = 0; i < s.length(); i++) {
char c = arr[i];
if (!charCount.containsKey(c)) {
charCount.put(c,1);
} else {
charCount.put(c,charCount.get(c)+1);
}
}
for (char c:charCount.keySet()) {
if (charCount.get(c) % 2 != 0) {
output.append(c);
}
}
return output.toString();
}
The problem lies in how you are selecting the output. HashSets and HashMaps do not have any ordering associated with them. In your test case, the output could be either ac OR ca .
To solve this, you can do a variety of things. The quickest way I see is to take your orignal string, lets say s, and call
s.replace(c,"")
for ever char you need to remove.
I doubt this is anywhere near the most, or even mildly, efficient way to solve this, but it should work.

Using " this" in java

I have been given a code and need to "fill in the blanks", for one part of the problem I need to write a method that will check that a string has only letters from the alphabet ( no commas or periods or numbers) and then if there are upper case letters, convert them to lower case.
I think I understand how to write this, however this is part of the code that is given
public Message (String m){
message = m;
lengthOfMessage = m.length();
this.makeValid();
The method I have to write is the makeValid one, but I'm not sure how to use the this.makeValid and how to write the code if the method doesn't take a string as the argument?
Note: I understand now that I can use message and lengthOfmessage but i am still trying to wrap my head around it.
would this code make sense and make proper use of the this
public void makeValid(){
for (int i = 0; i < lengthOfMessage ; i++ ) {
char mchar = message.charAt(i);
if (64 <= mchar && mchar<= 90) {
mchar = (char)((mchar + 32));
builder.append(mChar);
}
}
}

Java 8 : How to REDUCE compile time for the following code?

How to improve the performance of this code, reducing the compile time and keeping the functionality of the code same ?
The code is to extract two sub-strings from different strings and concatinating them to provide the largest possible palindromic string.
the Question was :You have two strings, (a) and (b). Find a string, (c), such that: (c)=(d)+(e).
(d),(e) can be expressed as where (d) is a non-empty substring of (a) and (e) is a non-empty substring of (b).
(c) is a palindromic string.
The length of is as long as possible.
For each of the pairs of strings (a) and (b) received as input, find and print string on a new line. If you're able to form more than one valid string , print whichever one comes first alphabetically. If there is no valid answer, print -1 instead.
import java.io.*;
import java.util.*;
public class Solution {
boolean isPalindrome(String s) {
int n = s.length();
for (int i=0;i<(n / 2);++i) {
if (s.charAt(i) != s.charAt(n - i - 1)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
String result="";
Scanner in = new Scanner(System.in);
int n = in.nextInt();
for(int a=0; a<n; a++)
{int length1, length2, i,c,d,j;
int max_length=0;
String string1 = in.next();
String sub1,sub2;
String string2 = in.next();
length2=string2.length();
length1 = string1.length();
for( c = 0 ; c <length1 ; c++ )
{
for( i = length1-c ; i >0 ; i-- )
{
sub1 = string1.substring(c, c+i);
for( d = 0 ; d < length2 ; d++ )
{
for( j = length2-d ; j >0 ; j-- )
{
sub2 = string2.substring(d, d+j);
String temp=sub1+sub2;
Solution obj= new Solution();
if(temp.length()>=max_length && obj.isPalindrome(temp)==true)
{
if (max_length==temp.length())
{ if(temp.compareTo(result)<0)
{
result=temp;
}}
else {
max_length=temp.length();
result=temp;
}
}
}
}
}
}
if(max_length==0)
System.out.println(-1);
else
{
System.out.println(result);
result="";
}
} /* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
}
}
I assume you want to reduce execution time, as opposed to compile time.
It is always best to avoid guessing, and rather determine exactly how the time is spent.
This is a good example.
If you do have a guess, this will prove it, or disprove it by showing you what the real problem is.
I have a guess (and it's only a guess).
You have a three-level nested loop, and inside the innermost loop I see a bunch of things that look suspicious.
The biggest one is new Solution().
That hits the memory manager, which can be very costly, not only to make the objects, but to clean them up.
Maybe you could move that out of the inner loop.
After that comes String temp=sub1+sub2;, which also hits the memory manager to make a new string.
Maybe you could make use the the string builder.
After that comes isPalindrome.
Whether that is efficient or not, I don't know.
Finally, your code needs much more disciplined indentation.
That alone can cause all kinds of bugs due to not being able to follow what you're doing.

Generate patterns from a given string in java

Given a string str = ab12.
I'm trying to generate patterns as below
xbx2 ax1x abxx xx12
Here's one more example to make it a bit clear :
Original String 182d3c
Required pattern :
18xdxc 182x3x 18xx3c 182dxx 18xxxx See that 18 is constant and other two varying
x82dxc 1x2d3x xx2d3c 182dxx xx2dxx See now 2d is constant others are varying
so on and on...
Note that number of x in any pattern must be even.
I tried using regex but to no avail.
then i thought may be binary pattern generation algo will help (it seems somewhat like binary pattern with x), but still i'm not there. :(
If you need more info please comment, I'll be happy to share.
Any help would be greatly appreciated !
Thanks!
12 characters is a safe limit.
You can use bit-mask...Iterate through 0 to 2^l - 1, (where l = length of string) and check in the bit representation of i, if the number of set bits is even. If it is, mark the position of set bits as x's and keep the rest of the string.
This algorithm has complexity O(l * 2^l), which is fine as max(l) = 12. So, number of operations will be of the order 2.4e4, which is easily achievable in well under 1s.
EDIT: As requested, sample code in Java
EDIT2: Replaced previous code with new working code :)
import java.io.*;
import java.util.*;
import java.lang.*;
public class xes{
public static String convert(int n, int l){
StringBuilder s = new StringBuilder();
int g = 0;
while(n>0){
int c = n%2;
if(c==0)
s.append("0");
else{
s.append("1");
g++;
}
n/=2;
}
while(s.length()<l)
s.append("0");
if(g%2 == 0)
return ("" + s.reverse());
else
return "-1";
}
public static ArrayList<String> getAllPatterns(String s){
int l = s.length();
int p = (1<<l) - 1; //because you don't want all x's, so -1. 1<<l is same as power(2,l)
ArrayList<String> arr = new ArrayList<String>();
for(int i=1;i<p;i++){ //i started from i=1 since you don't want all characters visible in any string in arraylist...if you want, stat it with 0
String z = convert(i,l);
if(z.equals("-1"))
continue;
StringBuilder g = new StringBuilder(s);
for(int j=0; j < z.length(); j++){
if(z.charAt(j)=='1')
g.setCharAt(j,'x');
}
System.out.println(g);
arr.add("" + g);
}
return arr;
}
public static void main(String args[]){
ArrayList<String> patterns = getAllPatterns("1823");
}
}
This is the output:
18xx
1x2x
1xx3
x82x
x8x3
xx23
For another input, 1823ab, I'm getting all 30 possible (6C2 + 6C4) strings as output:
1823xx
182xax
182xxb
18x3ax
18x3xb
18xxab
18xxxx
1x23ax
1x23xb
1x2xab
1x2xxx
1xx3ab
1xx3xx
1xxxax
1xxxxb
x823ax
x823xb
x82xab
x82xxx
x8x3ab
x8x3xx
x8xxax
x8xxxb
xx23ab
xx23xx
xx2xax
xx2xxb
xxx3ax
xxx3xb
xxxxab

Categories