sort a string in recursion - java

I have a certain string and I want to sort it in recursion.
My code is error free but the algorithm is not working and I need help
The index will be zero when calling the function.
The main idea is the compare between indexes in the string and creating a new string each time with the new sequence of the letters compared.
each call I send the new string which was created in each run
private static String sort(String s1, int index)
{
String s2="";
if (index == s1.length()-2)
return s1;
else
{
if (s1.charAt(index) > s1.charAt(index+1))
{
for (int i = 0; i < s1.length(); i++)
{
if (index == i)
{
s2 += s1.charAt(index+1);
s2 += s1.charAt(index);
i += 2;
}
s2 += s1.charAt(i);
}
}
else
{
for (int i = 0; i < s1.length(); i++)
{
if (index == i)
{
s2 += s1.charAt(index);
s2 += s1.charAt(index+1);
i += 2;
}
s2 += s1.charAt(i);
}
}
return (sort(s2,++index));
}
}
input : acbacds
output: abaccds
the output should be : aabccds

Each call compares a pair of adjacent characters; if they're out of order, you switch them.
Your recursion simply replaces an outer loop running through the length of the array.
The end of this process guarantees that the largest value will now be at the end of the array. To this extent, it works correctly.
If you expect an array of N elements to get fully sorted, you must repeat this process up to N-1 times. The only reason your given example is so close is that the array you gave it is already very close to sorted.
Try again with something in reverse order, and you'll see the effect. For instance, use "hgfedcba". One pass will get you "gfedcbah", moving the 'h' from the front to the end.
If you want a working bubble sort, try searching here on SO or on the web overall.
Finally, you might look into the Java substring functions; building s2 a character at a time is hard on the eyes; it's also slow, especially in the case where you don't switch characters.

Related

Recursion: Longest Palindrome Substring

This is a very common problem in which we would have to find the longest substring which is also a palindrome substring for the given input string.
Now there are multiple possible approaches to this and I am aware about Dynamic programming solution, expand from middle etc. All these solutions should be used for any practical usecase.
I was experimenting with using recursion to solve this problem and trying to implement the simple idea.
Let us assume that s is the given input string and i and j represent any valid character indexes of input string. So if s[i] == s[j], my longest substring would be:
s.charAt(i) + longestSubstring(s, i + 1, j - 1) + s.charAt(j)
And if these two characters are not equal then:
max of longestSubstring(s, i + 1, j) or longestSubstring(s, i, j - 1)
I tried to implement this solution below:
// end is inclusive
private static String longestPalindromeHelper(String s, int start, int end) {
if (start > end) {
return "";
} else if (start == end) {
return s.substring(start, end + 1);
}
// if the character at start is equal to end
if (s.charAt(start) == s.charAt(end)) {
// I can concatenate the start and end characters to my result string
// plus I can concatenate the longest palindrome in start + 1 to end - 1
// now logically this makes sense to me, but this would fail in the case
// for ex: a a c a b d k a c a a (space added for visualization)
// when start = 3 (a character)
// end = 7 (again end character)
// it will go in recursion with start = 4 and end = 6 from now onwards
// there is no palindrome substrings apart from the single character
// substring (which are palindrome by itself) so recursion tree for
// start = 3 and end = 7 would return any single character from b d k
// let's say it returns b so result would be a a c a b a c a a
// this would be correct answer for longest palindrome subsequence but
// not substring because for sub strings I need to have consecutive
// characters
return s.charAt(start)
+ longestPalindromeHelper(s, start + 1, end - 1) + s.charAt(end);
} else {
// characters are not equal, increment start
String s1 = longestPalindromeHelper(s, start + 1, end);
String s2 = longestPalindromeHelper(s, start, end - 1);
return s1.length() > s2.length() ? s1 : s2;
}
}
public static String longestPalindrome(String s) {
return longestPalindromeHelper(s, 0, s.length() - 1);
}
public static void main(String[] args) throws Exception {
String ans = longestPalindrome("aacabdkacaa");
System.out.println("Answer => " + ans);
}
For a moment let us forgot about time complexity or runtime. I am focused towards making it work for simple case above.
As you can see in the comments I got the idea why this is failing but I tried hard to rectify the problem following the exactly same approach. I don't want to use loops here.
What could be the possible fix for this following same approach?
Note: I am interested in the actual string as answer and not the length. FYI I had a look at all the other questions and it seems no one is following this approach for correctness so I am trying.
Once you have a call wherein s[i] == s[j], you could flip a boolean flag or switch to a modified method that communicates to child calls that they can no longer use the "don't match, try i + 1 and j - 1" branch (else condition). This ensures you're looking at substrings, not subsequences, for the remainder of the recursion.
Secondly, for the substring variant, even if s[i] == s[j], you should also try i + 1 and j - 1 as if these characters didn't match, because one or both of these characters might not be part of the final best substring between i and j. In the subsequence version, there's never any reason not to add any matching characters to the current palindromic subsequence for the range i to j, but that's not always the case with substrings.
For example, given input "aabcbda" and we're at a call frame where i = 1 and j = length - 1, we need to maximize over three possibilities:
The best substring includes both 'a' characters. Call the subroutine with the flag that says we have to consume from both ends on down and can no longer try skipping characters.
The best substring might still include s[i] but not s[j], try j - 1.
The best substring might still include s[j] but not s[i], try i + 1.
Another observation: it might make more sense to pass best indices up the helper call chain, then grab the longest palindromic substring based on these indices at the very end in the wrapper function.
On a similar note, if you're struggling, you might simplify the problem and return the longest palindromic substring length using your recursive method, then switch to getting the actual substring itself. This makes it easier to focus on the subsequence logic without the return value complicating things as much.
It is much easier to use loops here, rather than recursion, something like this:
public static void main(String[] args) {
System.out.println(longestPalindrome("abbqa")); // bb
System.out.println(longestPalindrome("aacabdkacaa")); // aca
System.out.println(longestPalindrome("aacabdkaccaa")); // acca
}
public static String longestPalindrome(String str) {
String palindrome = "";
for (int i = 0; i < str.length(); i++) {
for (int j = i; j < str.length(); j++) {
String substring = str.substring(i, j);
if (isPalindrome(substring)
&& substring.length() > palindrome.length()) {
palindrome = substring;
}
}
}
return palindrome;
}
public static boolean isPalindrome(String str) {
for (int i = 0; i < str.length() / 2; i++) {
if (str.charAt(i) != str.charAt(str.length() - i - 1)) {
return false;
}
}
return true;
}

Remove same subnet proxies from text file

I want to remove same subnet proxies from a text file.
txt.file= proxy.txt
19.15.15.90:61234
19.15.15.29:28010
19.15.15.80:8998
19.15.15.102:8998
25.25.24.15:8998
25.25.24.80:8998
210.192.38.25:8998
210.192.38.29:8998
I need output be
19.15.15.90:61234
25.25.24.15:8998
210.192.38.25:8998
It doesn't matter which proxies are removed, I just needs to keep 1 from each subnet.
subnet= first 3 numbers the same.
One potential solution1 is to add all the items to a List, sort the list, and then iterate over the list checking if the first n characters are the same as the previous entry, and if not, print it.
First, we'd need to get the third index of . in this scenario2:
public static int nthIndexOf(String text, char needle, int n) {
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == needle) {
n--;
if (n == 0) {
return i;
}
}
}
return -1;
}
Then simply perform the iteration as mentioned above:
for (int i = 1; i < list.size(); i++) {
int pos = nthIndexOf(list.get(i), '.', 3);
if (!list.get(i).substring(0, pos).equals(list.get(i - 1).substring(0, pos))) {
System.out.println(list.get(i));
}
}
Oh, and just print the first entry too, as it's going to be unique, considering it hasn't been compared to anything yet.
Of course, I am just printing System.out.println(list.get(i));, but do whatever is necessary with it there.
Example
1There may be edge cases I've missed, but that's up to you to check
2Credit where credit is due

Java concatenate 4 strings then truncate

working on a Java issue
I've got 4 strings:
s1, s2, s3, s4 that I must concatenate together into one. If the subsequent resulting string is longer than 75 characters, I then need to truncate, but starting with s1 and truncate the right most characters of that string until it fits into 75 with the other 3. If I end up removing all the characters in s1, then proceed with s2 truncation, again from the right most character, until s2+s3+s4 <=75 and so on.
Any simple way to accomplish this? I've been thinking of a while() loop but it gets pretty complicated when I'm checking s1+s2+s3+s4 and then truncating one string at a time.
Anyone done something similar and have a good solution?
You need to operate not with strings but with its length.
Get sum of length of all strings
Check which string need to truncate
Get sum beginning from truncated string.
Add up the lengths of the strings.
If the result is greater than 75, calculate the number of chars to truncate.
Truncate the first string until you either truncated the correct number of chars, or the first string is empty.
In the later case repeat with string 2 and so on.
After that concatenate the resulting strings.
Now you just need to translate the prose into java code :-)
String s1, s2, s3, s4;
ArrayList<String> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
int len = 0;
for(String s : list)
len += s.length();
if(len > 75)
{
int diff = len - 75;
for(int i = 0; i < list.size() && diff > 0; i++) {
String s = list.get(i);
int len = s.length();
if(len < diff)
list.set(i, null);
else {
s = s.subString(0, s.length() - diff);
list.set(i, s);
}
diff -= len;
}
}
String result = "";
for(String s : list) {
if(s != null) {
// concat ..
}
}

Matching subsequence of length 2 (at same index) in two strings

Given 2 strings, a and b, return the number of the positions where they contain the same length 2 substring. For instance a and b is respectively "xxcaazz" and "xxbaaz" yields 3, since the "xx", "aa", and "az" substrings appear in the same place in both strings.
What is wrong with my solution?
int count=0;
for(int i=0;i<a.length();i++)
{
for(int u=i; u<b.length(); u++)
{
String aSub=a.substring(i,i+1);
String bSub=b.substring(u,u+1);
if(aSub.equals(bSub))
count++;
}
}
return count;
}
In order to fix your solution, you really don't need the inner loop. Since the index should be same for the substrings in both string, only one loop is needed.
Also, you should iterate till 2nd last character of the smaller string, to avoid IndexOutOfBounds. And for substring, give i+2 as second argument instead.
Overall, you would have to change your code to something like this:
int count=0;
for(int i=0; i < small(a, b).length()-1; i++)
{
String aSub=a.substring(i,i+2);
String bSub=b.substring(i,i+2);
if(aSub.equals(bSub))
count++;
}
}
return count;
Why I asked about the length of string is, it might become expensive to create substrings of length 2 in loop. For length n of smaller string, you would be creating 2 * n substrings.
I would rather not create substring, and just match character by character, while keeping track of whether previous character matched or not. This will work perfectly fine in your case, as length of substring to match is 2. Code would be like:
String a = "iaxxai";
String b = "aaxxaaxx";
boolean lastCharacterMatch = false;
int count = 0;
for (int i = 0; i < Math.min(a.length(), b.length()); i++) {
if (a.charAt(i) == b.charAt(i)) {
if (lastCharacterMatch) {
count++;
} else {
lastCharacterMatch = true;
}
} else {
lastCharacterMatch = false;
}
}
System.out.println(count);
The heart of the problem lies with your usage of the substring method. The important thing to note is that the beginning index is inclusive, and the end index is exclusive.
As an example, dissecting your usage, String aSub=a.substring(i,i+1); in the first iteration of the loop i = 0 so this line is then String aSub=a.substring(0,1); From the javadocs, and my explanation above, this would result in a substring from the first character to the first character or String aSub="x"; Changing this to i+2 and u+2 will get you the desired behavior but beware of index out of bounds errors with the way your loops are currently written.
String a = "xxcaazz";
String b = "xxbaaz";
int count = 0;
for (int i = 0; i < (a.length() > b.length() ? b : a).length() - 1; i++) {
String aSub = a.substring(i, i + 2);
String bSub = b.substring(i, i + 2);
if (aSub.equals(bSub)) {
count++;
}
}
System.out.println(count);

More efficient way to find all combinations?

Say you have a List of Strings or whatever, and you want to produce another List which will contain every possible combination of two strings from the original list (concated together), is there any more efficient way to do this other than using a nested for loop to combine the String with all the others?
Some sample code:
for(String s: bytes) {
for(String a: bytes) {
if(!(bytes.indexOf(a) == bytes.indexOf(s))) {
if(s.concat(a).length() == targetLength) {
String combination = s.concat(a);
validSolutions.add(combination);
}
}
}
}
The time for execution gets pretty bad pretty quickly as the size of the original list of Strings grows.
Any more efficient way to do this?
You can avoid checking i != j condition by setting j = i + 1. Also, things like bytes.length() get evaluated at each iteration of both loops - save it into a value and reuse. Calling a.length() inside the loop asks for a length of the same string multiple times - you can save some runtime on that as well. Here are the updates:
int len = bytes.length();
int aLength;
String a, b;
for(int i=0; i<len; i++) {
a = bytes[i];
aLength = a.length();
for(int j=i; j<len; j++) {
b = bytes[j];
if (b.length() + aLength == targetLength) {
validSolutions.add(b.concat(a));
validSolutions.add(a.concat(b));
}
}
}
Edit: j = i because you want to consider a combination of a string with itself; Also, you'd need to add a.concat(b) as well since this combination is never considered in the loop, but is a valid string
You can't get Better than O(N^2), because there are that many combinations. But you could speed up your algorithm a bit (from O(N^3)) by removing the indexOf calls:
for(int i=0; i<bytes.length(); i++) {
for(int j=0; j<bytes.length(); j++) {
string s = bytes[i];
string a = bytes[j];
if (i != j && s.length() + a.length() == targetLength) {
validSolutions.add(s.concat(a));
}
}
}
In addition to what Jimmy and lynxoid say, the fact that the total length is constrained gives you a further optimization. Sort your strings in order of length, then for each s you know that you require only the as such that a.length() == targetLength - s.length().
So as soon as you hit a string longer than that you can break out of the inner loop (since all the rest will be longer), and you can start at the "right" place for example with a lower-bound binary search into the array.
Complexity is still O(n^2), since in the worst case all the strings are the same length, equal to half of totalLength. Typically though it should go somewhat better than considering all pairs of strings.

Categories

Resources