Java Decode Run Length Assignment - java

Here's the basics of the assignment:
Your task is to write a program that decodes a sequence of characters which was encoded using a simple form of run-length encoding, as described by the rules below.
Any sequence of between 2 to 9 identical characters is encoded by two characters. The first character is the length of the sequence, represented by one of the characters 2 through 9. The second character is the value of the repeated character. A sequence of more than 9 identical characters is dealt with by first encoding 9 characters, then the remaining ones.
Any sequence of characters that does not contain consecutive repetitions of any characters is represented by a 1 character followed by the sequence of characters, terminated with another 1. If a 1 appears as part of the sequence, it is escaped with a 1, thus two 1 characters are output.
Example Input and Output:
Input:
9A1ABC131
1112 3124
111111
Output:
AAAAAAAAAABC111
12 344
11
My code that I have so far but doesn't quite work:
import java.util.Scanner;
public class RunLength {
public static void main(String[] args) {
Scanner kb = new Scanner(System.in);
String test = kb.nextLine();
System.out.println(decode(test));
}
public static String encode(String s) {
if (s == "" || s == null) return "";
StringBuffer sb = new StringBuffer();
int count = 0;
char ch = 0;
for (int i = 0; i < s.length(); i++) {
if (i == 0) {
ch = s.charAt(i);
count++;
} else {
if (ch == s.charAt(i)) {
count++;
} else {
sb.append(ch).append(count);
count = 1; // count is set to 1 as 1 occurrence of ch has been appended to the output
ch = s.charAt(i);
}
}
}
sb.append(ch).append(count);
return sb.toString();
}
public static String decode(String st) {
if (st == "" || st == null) return "";
char[] stArr = st.toCharArray();
char lastseen = 0;
StringBuffer sb = new StringBuffer();
for (char s : stArr) {
if (!Character.isDigit(s)) {
lastseen = s;
sb.append(s);
} else {
int n = Integer.parseInt(String.valueOf(s));
for (int i = 0; i < n - 1; i++) {
sb.append(lastseen);
}
}
}
return sb.toString();
}
public static int[] decode2(String source) {
int arrLength = 0;
for (int i = 0; i < source.length(); i += 2) {
int count = Character.getNumericValue(source.charAt(i));
arrLength += count;
}
int array[] = new int[arrLength];
int k = 0;
for (int i = 0; i < source.length(); i += 2) {
int count = Character.getNumericValue(source.charAt(i));
for (int j = 0; j < count; j++) {
array[i + k] = Character.getNumericValue(source.charAt(i + 1));
}
}
return array;
}
}

I suggest you try to split your decode methods into two main logical parts:
One for the case that you are actually performing a RLE and the other for the case where you have a sequence of non-repeated characters, in which 1s have to be escaped.
The latter is easy to implement and your solution for that part seems to be correct.
The former needs you to loop over the next characters until the end of the sequence has been found.
If you read anything but a 1, just add it to the output.
In case there is a 1, you need to look ahead at the next character to see whether there is another 1, meaning there is an unrepeated 1 that had to be escaped, which is to be added to the output (consuming the lookahead, too). If the look ahead is not a 1 (including the special case where there is no next character) the unrepeated characters sequence ends here and nothing is to be added to the output.
Since this page is not supposed to solve your homework, I won't post a complete solution, though.

Related

Print the length of maximum subsequence of '1' s

import java.util.Scanner;
class Motu
{
// Returns length of the longest subsequence
// of the form 0*1*0*
public static int longestSubseq(String s)
{
int n = s.length();
int[] count_1 = new int[n + 1];
count_1[0] = 0;
for (int j = 1; j <= n; j++)
{
count_1[j] = count_1[j - 1];
if (s.charAt(j - 1) != '0')
count_1[j]++;
}
// Compute result using precomputed values
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
ans = Math.max(count_1[j] - count_1[i - 1] , ans);
return ans;
}
// Driver code
public static void main(String[] args)
{
#SuppressWarnings("resource")
Scanner sc=new Scanner(System.in);
String s =sc.next();
System.out.println(longestSubseq(s));
}
}
I am trying to make a program to get maximum sequences 1 in a string containing 0's & 1's. But I am unable to make out the logic for it, my program prints a number of 1's in the string which is not my desired output.
Sample input:- 0011100111100
output:- 4
You're quite good, but you're missing one thing : if the char is '0' : reset the counter to zero
for (int j = 1; j <= n; j++) {
if (s.charAt(j - 1) != '0')
count_1[j] = count_1[j - 1] + 1;
else
count_1[j] = 0;
}
But that can be done in one loop only, count with an int, and keep track of the max
public static int longestSubseq(String s) {
int ans = 0;
int count = 0;
for (char c : s.toCharArray()) {
if (c == '1')
count++;
else
count = 0;
ans = Math.max(ans, count);
}
return ans;
}
public static int longestSubSequence(String str, char ch) {
int res = 0;
int count = 0;
for (int i = 0; i < str.length(); i++) {
count = str.charAt(i) == ch ? count + 1 : 0;
res = Math.max(res, count);
}
return res;
}
The input string may be split by the characters that are not 1 (thus all non-1 characters are ignored and subsequences containing only 1 remain), and then the max length of the remaining parts can be found using Stream API:
public static int longestSubSequence(String str, char ch) {
return Arrays.stream(str.split("[^" + ch + "]"))
.mapToInt(String::length)
.max()
.orElse(0);
}
Similarly, a matching pattern can be created, and the max length of the group can be found:
public static int longestSubSequence(String str, char ch) {
return Pattern.compile(ch + "+")
.matcher(str)
.results()
.map(MatchResult::group)
.mapToInt(String::length)
.max()
.orElse(0);
}
Test:
System.out.println(longestSubSequence("00111011001111", '1')); // 4
It's worth mentioning that the characters other than '0' and '1' may be present in the input string, only subsequences of the given char are counted.
As an alternative to the other answers that work with a for-loop:
You could split the sequence into groups of ones with regex. Next, just iterate over the groups and update the count, if the length of the group is bigger than the previous length.
The first group will be 111 and the next one 1111. Thus the count will first be 3 and then it will be updated to 4.
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class CountSubsequence {
public static void main(String []args){
String sequence = "0011100111100";
Pattern pattern = Pattern.compile("(1+)");
Matcher matcher = pattern.matcher(sequence);
int count = 0;
while (matcher.find()) {
int currentLength = matcher.group().length();
if (currentLength > count) count = currentLength;
}
System.out.println(count); // 4
}
}
Since regex is not that performant you might want to use the for-loop in case you care for performance - but that just matters if you execute it a lot.

Repeating 3 letters up to 6 times only

I've been trying to use nested for loops to repeat the word, "hedgehog" with three letters up to 6 times only, however, it keeps going until it fully spells hedgehog.
public static String print3LetterSubstrings(String word) {
for (int len = 3; len <= word.length(); len++) {
for (int i = 0; i+len <= word.length(); i++) {
System.out.println(word.substring(i, i+len));
}
}
return word;
}
What I want is to have just 3 letters that just repeat 6 times.
hed
edg
dge
geh
eho
hog
If you always want three character substring(s) then len shouldn't change. You want to loop printing the substring from i to i + len. Like,
public static String print3LetterSubstrings(String word) {
int len = 3;
for (int i = 0; i + len <= word.length(); i++) {
System.out.println(word.substring(i, i + len));
}
return word;
}
Outputs when called as print3LetterSubstrings("hedgehog"); (as requested)
hed
edg
dge
geh
eho
hog

in repeated string finding the total number of time the occurrence of any character

Given an integer,n, find and print the number of letter a's in the first n letters of infinite string.
For example, if the string s='abcac' and n=10, the substring we consider is abcacabcac , the first 10 characters of her infinite string. There are 4 occurrences of a in the substring.
static long repeatedString(String s, long n) {
long len = s.length(), count = 0;
StringBuilder sb = new StringBuilder("");
char[] c = s.toCharArray();
for (int i = 0; i < n; i++) {
sb.append(c[(i % len)]);
if (sb.charAt(i) == 'a')
count++;
}
return count;
}
it is showing error
incompatible types: possible lossy conversion from long to int
sb.append(c[i%len]);
if i am type casting the len then it is not passing the test case for the value whose length is greater than 10^9 for example if my input is
a
1000000000000
then the output must be 1000000000000
note-> for any given input i have to calculate the total number of 'a'
present in that given string
EDIT:i am calling my function as
long result = repeatedString("a", 1000000000000);
Part of your question seemed a bit vague, but from the last line, I get that, you want to find number of occurrences of a particular character in a string.
You can use a HashMap to add the unique characters of your String and set the value as the number of occurrences of the character.
What I am saying, looks something like this in code:
HashMap<Character,Integer> hm = new HashMap<Character,Integer>();
char[] str = s.toCharArray();
for(char c : str) {
if(hm.containsKey(c))
hm.put(c, hm.get(c)+1);
else
hm.put(c, 1);
}
Now you can just choose the character of your choice in the string to get it's number of occurrences, like this:
if(hm.get(character)!=null)
ans = hm.get(character);
else
ans = 0;
There is also a library, I am making for this here.
Edit:
From the edit, the question is much more clear, for that all you need to do is to add the characters of your string to the previous string, until the length is met.
After that, you can use the new string like in the code, I've given here.
You don't need a StringBuilder.
Get the result you want by iterating the initial string and multiply it as many times as needed, meaning by (n / len), then add what is left by the division:
static long repeatedString(String s, long n) {
long len = s.length();
if (len == 0)
return 0;
long rep = n / len;
long count = 0;
for (int i = 0; i < len; i++) {
if (s.charAt(i) == 'a')
count++;
}
count *= rep;
long rest = n % len;
for (int i = 0; i < rest; i++) {
if (s.charAt(i) == 'a')
count++;
}
return count;
}
I think you do not have to use StringBuidler (moreover, for big n, this could flow OutOfMemoryError), but count required letters on the fly.
public static long repeatedString(String str, long n, char ch) {
long count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == ch)
continue;
count += n / str.length();
count += i < n % str.length() ? 1 : 0;
}
return count;
}

Java program to find the letter that appears in the most words?

I have a sentence, and I want to find the char that appears in the most words, and how many words it appears in.
For example: "I like visiting my friend Will, who lives in Orlando, Florida."
Which should output I 8.
This is my code:
char maxChar2 = '\0';
int maxCount2 = 1;
for (int j=0; j<strs2.length; j++) {
int charCount = 1;
char localChar = '\0';
for (int k=0; k<strs2[j].length(); k++) {
if (strs2[j].charAt(k) != ' ' && strs2[j].charAt(k) != maxChar2) {
for (int l=k+1; l<strs2[j].length(); l++) {
if (strs2[j].charAt(k)==strs2[j].charAt(l)) {
localChar = strs2[j].charAt(k);
charCount++;
}
}
}
}
if (charCount > maxCount2) {
maxCount2 = charCount;
maxChar2 = localChar;
}
}
, where strs2 is a String array.
My program is giving me O 79. Also, uppercase and lowercase do not matter and avoid all punctuation.
As a tip, try using more meaningful variable names and proper indentation. This will help a lot especially when your program is not doing what you thought it should do. Also starting smaller and writing some tests for it will help a bunch. Instead of a full sentence, get it working for 2 words, then 3 words, then a more elaborate sentence.
Rewriting your code to be a bit more readable:
// Where sentence is: "I like".split(" ");
private static void getMostFrequentLetter(String[] sentence) {
char mostFrequentLetter = '\0';
int mostFrequentLetterCount = 1;
for (String word : sentence) {
int charCount = 1;
char localChar = '\0';
for (int wordIndex = 0; wordIndex < word.length(); wordIndex++) {
char currentLetter = word.charAt(wordIndex);
if (currentLetter != ' ' && currentLetter != mostFrequentLetter) {
for (int l = wordIndex + 1; l < word.length(); l++) {
char nextLetter = word.charAt(l);
if (currentLetter == nextLetter) {
localChar = currentLetter;
charCount++;
}
}
}
}
if (charCount > mostFrequentLetterCount) {
mostFrequentLetterCount = charCount;
mostFrequentLetter = localChar;
}
}
}
Now all I did was rename your variables and change your for loop to a for-each loop. By doing this you can see more clearly your algorithm and what you're trying to do. Basically you're going through each word and comparing the current letter with the next letter to check for duplicates. If I run this with "I like" i should get i 2 but instead I get null char 1. You aren't properly comparing and saving common letters. This isn't giving you the answer, but I hope this makes it more clear what your code is doing so you can fix it.
Here is a somewhat more elegant solution
public static void FindMostPopularCharacter(String input)
{
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
input = input.toUpperCase();
HashMap<Character, Integer> charData = new HashMap<>();
char occursTheMost = 'A'; //start with default most popular char
int maxCount = 0;
//create the map to store counts of all the chars seen
for(int i = 0; i < alphabet.length(); i++)
charData.put(alphabet.charAt(i), 0);
//first find the character to look for
for(int i = 0; i < input.length(); i++)
{
char c = input.charAt(i);
//if contained in our map increment its count
if(charData.containsKey(c))
charData.put(c, charData.get(c) + 1);
//check for a max count and set the values accordingly
if(charData.containsKey(c) && charData.get(c) > maxCount)
{
occursTheMost = c;
maxCount = charData.get(c);
}
}
//final step
//now split it up into words and search which contain our most popular character
String[] words = input.split(" ");
int wordCount = 0;
CharSequence charSequence;
for(Character character : charData.keySet())
{
int tempCount = 0;
charSequence = "" + character;
for(int i = 0; i < words.length; i++)
{
if(words[i].contains(charSequence))
tempCount++;
}
if(tempCount > wordCount)
{
occursTheMost = character;
wordCount = tempCount;
}
}
System.out.println(occursTheMost + " " + wordCount);
}
Output of
String input = "I like visiting my friend Will, who lives in Orlando, Florida.";
FindMostPopularCharacter(input);
is
I 8
Note: If there are ties this will only output the character that first reaches the maximum number of occurrences.
FindMostPopularCharacter("aabb aabb aabb bbaa");
Outputs
B 4
because B reaches the max first before A due to the last word in the input.
FindMostPopularCharacter("aab aab b")
B 3

Java String: Checking for consecutive letters or numbers

Problem: I am playing around in Java and I am trying to count consecutive 'characters' within a string.
Example:
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String binaryString = Integer.toBinaryString(n);
The above code returns a binary string of the integer value entered. If we input the number 5 this will return: 101
I now wish to loop through the String and check if there are any consecutive 1's within the String.
for (int i = 0; i < binaryString.lenth(); i++)
{
// code comes here...
}
I am not sure how I can check this. I have tried the following:
for (int i = 0; i < binaryString.length(); i++)
{
char charAtPos = binaryString.charAt(i);
char charAtNextPos = binaryString.charAt(i+1);
if (charAtPos == '1')
{
if (charAtPos == charAtNextPos)
{
consecutive += 1;
}
}
}
But this obviously throws an ArrayIndexOutOfBounds as i+1 will produce a number larger than the array length.
Thank you in advance for your answers.
Owen
try running the for loop for size one less than the length of the strin
for (int i = 0; i < (binaryString.length()-1); i++)
{
char charAtPos = binaryString.charAt(i);
char charAtNextPos = binaryString.charAt(i+1);
if (charAtPos == '1')
{
if (charAtPos == charAtNextPos)
{
consecutive += 1;
}
}
}
You only need 1 line:
binaryString.split("1(?=1)").length() - 1;
We can still simplify your code using and operator
import java.util.Scanner;
class StackBinary
{
public static void main(String args[])
{
Scanner in = new Scanner(System.in);
String n = Integer.toBinaryString(in.nextInt());
for (int i = 0; i < n.length()-1; i++)
{
char charAtPos = n.charAt(i);
char charAtNextPos = .charAt(i+1);
if (charAtPos == '1' && charAtNextPos == '1')
{
consecutive+=1;
}
}
}

Categories