Cant remove all chars from a string before a "special one" - java

I tried coding a complete decimal to binary converter, which worked just fine and now I want to remove the unnecessary 0s from my output String, but it doesnt remove all of the 0s and I have no idea why.
Here is my code :
public class Converter {
private static final int[] ARRAY = {16348,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1};
public static String toBinary(int number) {
String output = new String();
int number2 = number;
for (int i=0; i<ARRAY.length ; i++) {
if (number2 - ARRAY[i] >= 0) {
output += "1";
number2 -= ARRAY[i];
}
else {
output += "0";
}
}
boolean sorted = false;
int i = 0 ;
while (sorted == false) {
if (output.charAt(i) == '0') {
StringBuilder temp = new StringBuilder(output);
temp.deleteCharAt(i);
output = temp.toString();
i ++;
}
else{
sorted = true;
}
}
return output;
}
}

It's because the variable i is pointing to a wrong location. It's because after you remove the 0 at the ith you are incrementing i.
For example, take the string 00001 (a minified one in terms of number of bits)
When i = 0, after removing the 0 at index i we get 0001. On incrementing i becomes 1.
When i = 1, after removing the 0 at index i we get 001. On incrementing i becomes 2.
(We have already skipped past the first 0).
Removing i++ will do the trick. Still, your code does not work for input 0. In your while loop, you still need to validate the index i and break the while loop by checking if output string is empty.
A simple solution would be to use Integer.valueOf as suggested in this answer.
Or another one-liner would be:
String result = output.contains("1") ? output.substring(output.indexOf("1")) : "0";

I suggest to use simpler solution to remove trailing zero's by parsing the output to Integer
use this
int x = Integer.valueOf(output);
// if you wanted the output as string
String val = String.valueOf(x);

It is preferable that you don't add the leading zeroes in the first place. Why create, then remove? This method will not add leading zeroes until a one has been detected:
public static String toBinary(int number) {
String output = new String();
int number2 = number;
boolean foundOne = false;
for (int i=0; i<ARRAY.length ; i++) {
if (number2 - ARRAY[i] >= 0) {
output += "1";
number2 -= ARRAY[i];
foundOne = true;
}
else if (foundOne){
output += "0";
}
}
if (!foundOne)
output = "0";
return output;
}

String s = "00010101"
System.out.println(s.replaceAll("^0*", ""))
// => 10101
This is a example using regex.
^ means the expression should only match at the beginning of a string.
0*matches any string of characters that repeats 0 zero or more times

Related

Is there any way to sort the digits of an Integer without any ARRAY in JAVA?

I am trying to sort the digits of an Integer in descending order in JAVA but I am not allowed to use any array.
This was given to me as an assignment in class and below is a code that I tried but failed.
import java.util.Scanner;
class descend
{
public static void main(String args[])
{
int a=0,loc=0,parse=0,temp=0,big=0;
Scanner scan = new Scanner(System.in);
System.out.print("Enter a number");
a=scan.nextInt();
String s=Integer.toString(a);
int l=s.length();
for(int i=0;i<l;i++)
{
big=(int)(s.charAt(i));
loc=i;
for(int j=i+1;j<l;j++)
{
parse=(int)(s.charAt(j));
if(parse>big)
{
big = parse;
loc=j;
}
}
temp=parse;
s.charAt(i)=s.charAt(loc);
s.charAt(loc)=temp
}
System.out.print(s);
}
}
Here I get a syntax error at s.charAt(i)=s.charAt(loc); and s.charAt(loc)=temp; that a variable is required but a value is given.
Please help me out with this and I shall always be grateful to you.
Maybe the teacher want to test your knowledge about the new stream API. Or maybe he wants you to test your knowledge about Collections.sort() and LinkedList (which does not contain an internal array).
1.) Here is a solution with stream API:
int number = 52214;
String.valueOf(number).chars()
.sorted()
.map(Character::getNumericValue).forEach(System.out::print);
This will print out:
12245
2.) Here is a solution with collections:
List<Integer> list = new LinkedList<Integer>();
StringCharacterIterator iterator = new StringCharacterIterator(String.valueOf(number));
for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next())
{
list.add(Character.getNumericValue(c));
}
Collections.sort(list);
System.out.println("list=" + list);
This will print out:
list=[1, 2, 2, 4, 5]
String cannot be changed, only replaced, hence a = b; f(b); will never change a.
With 10 digits only, you could iterate, step through, from 0 upto 9 to have the sorting:
int number = ... // or String number
if (number == 0) { // or < 10
System.out.println(number);
} else {
for (int digit = 0; digit <= 9; ++digit) {
// While being able to remove the current digit:
for (;;) {
int scrapedNumber = numberWithoutDigitOnce(number, digit);
if (scrapedNumber == number) {
break;
}
number = scrapedNumber;
System.out.print(digit);
}
}
System.out.println();
}
int numberWithoutDigitOnce(int number, int digit) {
if (number % 10 == digit) {
return number / 10;
}
int n = numberWithoutDigitOnce(number/10, digit)*10 + (number % 10);
}
Zero is a special case.
A recursive solution, you find the highest digit in the String, add it to your output String, and remove it from your input String.
Repeat until your input String is empty.
Removing the character at a given index in a String can be achieve by concatenating the characters before the index and the ones after the index. (Or with a StringBuilder but I agree with the comments on the OP that it would be cheating to use a StringBuilder)
private static String sort(String digitsLeftToSort, String sortedString) {
if(digitsLeftToSort.length() == 0) { // no more character to sort
return sortedString;
} else {
// find the index of the highest digit
int index = findIndexOfHighestDigit(digitsLeftToSort);
// add the character at that index to your output String
sortedString += digitsLeftToSort.charAt(index);
// Remove it from your input String
digitsLeftToSort = digitsLeftToSort.substring(0, index) + digitsLeftToSort.substring(index+1);
// Recursive call with your new Strings
return sort(digitsLeftToSort, sortedString);
}
}
// This finds the index of the highest digit in the given String
private static int findIndexOfHighestDigit(String s) {
int highestDigitValue = -1;
int highestDigitIndex = -1;
int integerValue;
for(int i = 0; i< s.length(); i++) {
integerValue = Character.getNumericValue(s.charAt(i));
if(integerValue > highestDigitValue) {
highestDigitValue = integerValue;
highestDigitIndex = i;
}
}
return highestDigitIndex;
}
Then
String sortedString = sort("462375623478142", "");
System.out.println(sortedString);
Outputs
877665444332221
Sorry, But after applying so much effort, I figured it out.
int n=54321;char ch;
String s=Integer.toString(n);
int l= s.length();
for(int i=48;i<=57;i++) //ascii values from 0 - 9
{
for(int j=0;j<l;j++)
{
ch=s.charAt(j);
if(ch==(char)i) // checking if a digit equals a number
{
System.out.print(ch);
}
}
}
It sorts the digits in ascending order. To sort in descending order we should use
for(int i=57;i>=48;i--)

Recursively decompressing a String

I have this assignment that needs me to decompress a previously compressed string.
Examples of this would be
i4a --> iaaaa
q3w2ai2b --> qwwwaaibb
3a --> aaa
Here's what I've written so far:
public static String decompress(String compressedText)
{
char c;
char let;
int num;
String done = "";
String toBeDone = "";
String toBeDone2 = "";
if(compressedText.length() <= 1)
{
return compressedText;
}
if (Character.isLetter(compressedText.charAt(0)))
{
done = compressedText.substring(0,1);
toBeDone = compressedText.substring(1);
return done + decompress(toBeDone);
}
else
{
c = compressedText.charAt(0);
num = Character.getNumericValue(c);
let = compressedText.charAt(1);
if (num > 0)
{
num--;
toBeDone = num + Character.toString(let);
toBeDone2 = compressedText.substring(2);
return Character.toString(let) + decompress(toBeDone) + decompress(toBeDone2);
}
else
{
toBeDone2 = compressedText.substring(2);
return Character.toString(let) + decompress(toBeDone2);
}
}
}
My return values are absolutely horrendous.
"ab" yields "babb" somehow.
"a" or any 1 letter string string yields the right result
"2a" yields "aaaaaaaaaaa"
"2a3b" gives me "aaaabbbbbbbbbbbbbbbbbbbbbbbbbbaaabbbbaaaabbbbbbbbbbbbbbbbbbbbbbbbbb"
The only place I can see a mistake in would probably be the last else section, since I wasn't entirely sure on what to do once the number reaches 0 and I have to stop using recursion on the letter after it. Other than that, I can't really see a problem that gives such horrifying outputs.
I reckon something like this would work:
public static String decompress(String compressedText) {
if (compressedText.length() <= 1) {
return compressedText;
}
char c = compressedText.charAt(0);
if (Character.isDigit(c)) {
return String.join("", Collections.nCopies(Character.digit(c, 10), compressedText.substring(1, 2))) + decompress(compressedText.substring(2));
}
return compressedText.charAt(0) + decompress(compressedText.substring(1));
}
As you can see, the base case is when the compressed String has a length less than or equal to 1 (as you have it in your program).
Then, we check if the first character is a digit. If so, we substitute in the correct amount of characters, and continue with the recursive process until we reach the base case.
If the first character is not a digit, then we simply append it and continue.
Keep in mind that this will only work with numbers from 1 to 9; if you require higher values, let me know!
EDIT 1: If the Collections#nCopies method is too complex, here is an equivalent method:
if (Character.isDigit(c)) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Character.digit(c, 10); i++) {
sb.append(compressedText.charAt(1));
}
return sb.toString() + decompress(compressedText.substring(2));
}
EDIT 2: Here is a method that uses a recursive helper-method to repeat a String:
public static String decompress(String compressedText) {
if (compressedText.length() <= 1) {
return compressedText;
}
char c = compressedText.charAt(0);
if (Character.isDigit(c)) {
return repeatCharacter(compressedText.charAt(1), Character.digit(c, 10)) + decompress(compressedText.substring(2));
}
return compressedText.charAt(0) + decompress(compressedText.substring(1));
}
public static String repeatCharacter(char character, int counter) {
if (counter == 1) {
return Character.toString(character);
}
return character + repeatCharacter(character, counter - 1);
}

Increasing number sequence in a string java

Problem: Check if the numbers in the string are in increasing order.
Return:
True -> If numbers are in increasing order.
False -> If numbers are not in increasing order.
The String sequence are :
CASE 1 :1234 (Easy) 1 <2<3<4 TRUE
CASE 2 :9101112 (Medium) 9<10<11<12 TRUE
CASE 3 :9991000 (Hard) 999<1000 TRUE
CASE 4 :10203 (Easy) 1<02<03 FALSE
(numbers cannot have 0 separated).
*IMPORTANT : THERE IS NO SPACES IN STRING THAT HAVE NUMBERS"
My Sample Code:
// converting string into array of numbers
String[] str = s.split("");
int[] numbers = new int[str.length];
int i = 0;
for (String a : str) {
numbers[i] = Integer.parseInt(a.trim());
i++;
}
for(int j=0;j<str.length;j++)
System.out.print(numbers[j]+" ");
//to verify whether they differ by 1 or not
int flag=0;
for(int j=0;j<numbers.length-1;j++){
int result=Integer.parseInt(numbers[j]+""+numbers[j+1]) ;
if(numbers[j]>=0 && numbers[j]<=8 && numbers[j+1]==numbers[j]+1){
flag=1;
}
else if(numbers[j]==9){
int res=Integer.parseInt(numbers[j+1]+""+numbers[j+2]) ;
if(res==numbers[j]+1)
flag=1;
}
else if(result>9){
//do something
}
}
This is the code I wrote ,but I cant understand how to perform for anything except one-digit-numbers ( Example one-digit number is 1234 but two-digit numbers are 121314). Can anyone have a solution to this problem?. Please share with me in comments with a sample code.
I'm gonna describe the solution for you, but you have to write the code.
You know that the input string is a sequence of increasing numbers, but you don't know how many digits is in the first number.
This means that you start by assuming it's 1 digit. If that fails, you try 2 digits, then 3, and so forth, until you've tried half the entire input length. You stop at half, because anything longer than half cannot have next number following it.
That if your outer loop, trying with length of first number from 1 and up.
In the loop, you extract the first number using substring(begin, end), and parse that into a number using Integer.parseInt(s). That is the first number of the sequence.
You then start another (inner) loop, incrementing that number by one at a time, formatting the number to text using Integer.toString(i), and check if the next N characters of the input (extracted using substring(begin, end)) matches. If it doesn't match, you exit inner loop, to make outer loop try with next larger initial number.
If all increasing numbers match exactly to the length of the input string, you found a good sequence.
This is code for the pseudo-code suggested by Andreas .Thanks for the help.
for (int a0 = 0; a0 < q; a0++) {
String s = in.next();
boolean flag = true;
for (int i = 1; i < s.length() / 2; i++) {
int first = Integer.parseInt(s.substring(0, i));
int k=1;
for (int j = i; j < s.length(); j++) {
if (Integer.toString(first + (k++)).equals(s.substring(j, j + i)))
flag = true;
else{
flag=false;
break;
}
}
if (flag)
System.out.println("YES");
else
System.out.println("NO");
}
I would suggest the following solution. This code generates all substrings of the input sequence, orders them based on their start index, and then checks whether there exists a path that leads from the start index to the end index on which all numbers that appear are ordered. However, I've noticed a mistake (I guess ?) in your example: 10203 should also evaluate to true because 10<203.
import java.util.*;
import java.util.stream.Collectors;
public class PlayGround {
private static class Entry {
public Entry(int sidx, int eidx, int val) {
this.sidx = sidx;
this.eidx = eidx;
this.val = val;
}
public int sidx = 0;
public int eidx = 0;
public int val = 0;
#Override
public String toString(){
return String.valueOf(this.val);
}
}
public static void main(String[] args) {
assert(check("1234"));
assert(check("9101112"));
assert(check("9991000"));
assert(check("10203"));
}
private static boolean check(String seq) {
TreeMap<Integer,Set<Entry>> em = new TreeMap();
// compute all substrings of seq and put them into tree map
for(int i = 0; i < seq.length(); i++) {
for(int k = 1 ; k <= seq.length()-i; k++) {
String s = seq.substring(i,i+k);
if(s.startsWith("0")){
continue;
}
if(!em.containsKey(i))
em.put(i, new HashSet<>());
Entry e = new Entry(i, i+k, Integer.parseInt(s));
em.get(i).add(e);
}
}
if(em.size() <= 1)
return false;
Map.Entry<Integer,Set<Entry>> first = em.entrySet().iterator().next();
LinkedList<Entry> wlist = new LinkedList<>();
wlist.addAll(first.getValue().stream().filter(e -> e.eidx < seq
.length()).collect(Collectors.toSet()));
while(!wlist.isEmpty()) {
Entry e = wlist.pop();
if(e.eidx == seq.length()) {
return true;
}
int nidx = e.eidx + 1;
if(!em.containsKey(nidx))
continue;
wlist.addAll(em.get(nidx).stream().filter(n -> n.val > e.val).collect
(Collectors.toSet()));
}
return false;
}
}
Supposed the entered string is separated by spaces, then the code below as follows, because there is no way we can tell the difference if the number is entered as a whole number.
boolean increasing = true;
String string = "1 7 3 4"; // CHANGE NUMBERS
String strNumbers[] = string.split(" "); // separate by spaces.
for(int i = 0; i < strNumbers.length - 1; i++) {
// if current number is greater than the next number.
if(Integer.parseInt(strNumbers[i]) > Integer.parseInt(strNumbers[i + 1])) {
increasing = false;
break; // exit loop
}
}
if(increasing) System.out.println("TRUE");
else System.out.println("FALSE");

Java read integer from middle of the string

Is it possible in Java to efficiently read an integer from random position of the string? For instance, I have a
String s = "(34";
if (s.charAt(0) == '(')
{
// How to read a number from position = 1 to the end of the string?
// Of course, I can do something like
String s1 = s.substring(1);
int val = Integer.parseInt(s1);
}
but it dynamically creates a new instance of string and seems to be too slow and performance hitting.
UPDATE
Well, to be precise: I have an array of strings in form "(ddd" where d is a digit. So I do know that a number starts always from pos = 1. How do I efficently read these numbers?
Integer.parseInt(s1.replaceAll("[\\D]", ""))
Answered before the update:
I'm not an expert in regex, but hope this "\\d+" is useful to you. Invoke the below method with pattern: "\\d+".
public static int returnInt(String pattern,String inputString){
Pattern intPattern = Pattern.compile(pattern);
Matcher matcher = intPattern.matcher(inputString);
matcher.find();
String input = matcher.group();
return Integer.parseInt(input);
}
Answered after the update:
String is a final object, you cannot edit it, so if you want to get some digit value from it, you have the 2 ways:
1. Use your code, that will work fine, but if you care about performance, try 2nd way.
2. Divide your string on digits and add them to get the result:
public static void main(String[] args) {
String input = "(123456";
if(input.charAt(0) == '(') {
System.out.println(getDigit(input));
}
}
private static int getDigit(String s) {
int result = 0;
int increase = 10;
for(int i = 1; i < s.length(); i++) {
int digit = Character.getNumericValue(s.charAt(i));
result*=increase;
result += digit;
}
return result;
}
Output:
123456
If you don't want to allocate a new String then you can use the code in this other SO answer:
int charArrayToInt(char[] data, int start, int end) throws NumberFormatException {
int result = 0;
for (int i = start; i < end; i++) {
int digit = ((int)data[i] & 0xF);
if ((digit < 0) || (digit > 9)) throw new NumberFormatException();
result *= 10;
result += digit;
}
return result;
}
You can call it with charArrayToInt(s.toCharArray(), 1, s.length())

Periodic Strings

I am trying to solve this String manipulation problem, where I need to find the smallest period of a given string.
A string is said to have period k if it can be formed by concatenating one or more repetitions of another string of length k.
For example, the string "abcabcabcabc" has period 3, since it is formed by 4 repetitions of the string "abc". It also has periods 6 (two repetitions of "abcabc") and 12 (one repetition of "abcabcabcabc"). Here's my code :
public static int getPeriod(String str){
int len=str.length();
boolean flag=false;
int i;
for (i=0;i<len;i++){
String s=str.substring(0,i);
String tmp=str;
while(tmp.length()>0){
if(tmp.startsWith(s)){
tmp=tmp.substring(0,i);
flag=true;
}
else {
flag=false;
continue;
}
}
if (flag==true)
break;
}
return i;
}
I am forming a string s by looping through the original string, one character at a time. After, that I am checking if the original string can be completely exhausted by concatenating the string s any number of times, or not.
ERROR:
The method always returns 0.
Why is that so ?
EDIT : My algorithm
Lets consider the input string HoHoHo
First step: s=H
tmp= HoHoHo
tmp= oHoHo (after substringing tmp)
'o' isn't the same as s, so we increase i
Second step:s=Ho
tmp= HoHoHo
tmp= HoHo (after substringing tmp)
tmp= Ho (after substringing tmp)
tmp= "" (after substringing tmp)
Return the value of i, that is 2.
The code inside the while loop isn't correct, it's called during the first invocation of the for loop with i=0 and hence the first assignment to the tmp variable sets it to the empty string, the loop exits and you get 0. The flag assignments and the continue in the else are not correct too.
Try this:
public static int getPeriod(String str) {
int len = str.length();
int i;
for (i = 1; i <= len/2; i++) {
String period = str.substring(0, i);
String tmp = str;
boolean flag = true;
while (flag && tmp.length() > 0) {
if (tmp.startsWith(period)) {
tmp = tmp.substring(i);
} else {
flag = false;
}
}
if (flag == true) {
return i;
}
}
return 0;
}
Notice that the for loop starts from 1 and goes to len/2 because you don't want to check for the zero length period and there can't be periods longer than n/2.
In the first loop iteration, i == 0, so s is "" (empty string), and tmp is also "" after the first iteration over while loop, so tmp also becomes "" and exits all the loops.
Starting with i = 0 will always return true because substring(0,0) will return the "" string and tmp.startsWith("") is always true.
First you should start i from 1, also you should replace continue with break, because continue will continue your while loop but what you want to do is continue the for loop and not the while loop
Here is a version of your code working:
public static int getPeriod(String str){
int len=str.length();
boolean flag=false;
int i;
for (i=1;i<len;i++){
String s=str.substring(0,i);
String tmp=str;
while(tmp.length()>0){
if(tmp.startsWith(s)){
tmp=tmp.substring(i);
flag=true;
}
else {
flag=false;
break;
// Replaced continue with break to exit the while loop and pass
// to the next value in the for loop
}
}
if (flag==true)
break;
}
return i;
}
I know this is an old question. The problem can be solved in linear time using Knuth's Prefix Function.
public static int prefixFunction(final String needle)
{
//This code does not include input validation. Validate the input and return appropriate error message
int[] pf = new int[needle.length()];
for (int i = 1; i < needle.length(); i++)
{
int j = pf[i - 1];
while (j > 0 && needle.charAt(i) != needle.charAt(j)) j--;
if (needle.charAt(i) == needle.charAt(j)) ++j;
pf[i] = j;
}
int n = needle.length(), maxValue = pf[n - 1];
if(maxValue == 0 || n%(n-maxValue) != 0) return -1; //Not periodic
return needle.length() - maxValue;
}

Categories

Resources