How to calculate possible missing characters? - java

I'm trying to get possible missing characters e.g:
input --> aa??bb there should be possible characters aaaabb & aaabbb & aabbbb so the result would be 3, Also ?a? would be 1.
Note:
aababb would be wrong, because it's not a right path for alphabet.
I'v done some code here but i couldn't get the perfect result yet.
may someone help me?
Scanner input = new Scanner(System.in);
String s = input.nextLine();
int possibleAlphabet = 1, oldPossibleAlphabet = 0;
for (int i = 0; i < s.length(); i++) {
oldPossibleAlphabet = 0;
System.out.print(s.charAt(i));
if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z' || s.contains("?")) {
if (s.charAt(i) == '?'){
for (int j = 0; j < i; j++) {
if (s.charAt(i - 1) == '?' && s.charAt(i + 1) == '?')
oldPossibleAlphabet++;
}
}
}else {
System.out.print( " ");
System.exit(0);
}
possibleAlphabet += oldPossibleAlphabet;
}
System.out.println(possibleAlphabet);

Check my code
public class Solution {
public static void main(String[] args) {
String str = "abc??cde???g?"; // Example
char[] arr = str.toCharArray();
int length = arr.length;
// Init value for count, start and end
int count = 0;
char start = 'a';
char end = 'a';
for (int i = 0; i < length; i++) {
if (arr[i] == '?') { // We found a question mark
boolean foundEnd = false;
int total = 1; // Currently the total of question mark is 1
for (int j = i + 1; j < length; j++) { // Count the total question mark for our method and the end character
if (arr[j] != '?') { // Not question mark
end = arr[j]; // Update end;
i = j -1;
foundEnd = true;
break;
} else {
total++;
}
}
if (!foundEnd) { // Change end to start in the case our question mark continue to the end of string
end = start;
}
// Start to counting and reset end to 'z'
int result = countPossibleCharacters(total, start, end);
if (count > 0) {
count *= result;
} else {
count += result;
}
end = 'z';
} else {
start = arr[i];
}
}
System.out.println("The total is : " + count);
}
/**
* Count the possible characters
* #param total the total question mark
* #param start the character in the left side of question mark
* #param end the character in the right side of question mark
* #return
*/
static int countPossibleCharacters(int total, char start, char end) {
if (total == 0) {
return 0;
}
if (total == 1) {
return end - start + 1;
}
if (total >= 2) {
int count = 0;
/**
* We have a range of characters from start to end
* and for each character we have 2 options: use or don't use it
*/
// We use it, so the total of question mark will be decrement by 1
count += countPossibleCharacters(total - 1, start, end);
// We don't use it, so the range of characters will be decrement by 1
if (start < end) {
count += countPossibleCharacters(total, ++start, end);
}
return count;
}
return 0;
}
}
Rules apply in my code
All characters in string are lowercase
Character on the left side must be lower than character on the right side
If we have a question mark in the beginning of string, we'll loop from 'a' to the next non question mark character
If we have question mark in the end of string, we'll replace it with previous non question mark character

Related

minimum operations required to make the longest character interval equal to K

I was asked this question in an contest.
Given a string containing only M and L, we can change any "M" to "L" or any "L" to "M". The objective of this function is to calculate the minimum number of changes we have to make in order to achieve the desired longest M-interval length K.
For example, given S = "MLMMLLM" and K = 3, the function should return 1. We can change the letter at position 4 (counting from 0) to obtain "MLMMMLM", in which the longest interval of letters "M" is exactly three characters long.
For another example, given S = "MLMMMLMMMM" and K = 2, the function should return 2. We can, for example, modify the letters at positions 2 and 7 to get the string "MLLMMLMLMM", which satisfies the desired property.
Here's what I have tried till now, but I am not getting correct output:
I am traversing the string and whenever longest char count exceeds K, I'm replacing M with L that point.
public static int solution(String S, int K) {
StringBuilder Str = new StringBuilder(S);
int longest=0;int minCount=0;
for(int i=0;i<Str.length();i++){
char curr=S.charAt(i);
if(curr=='M'){
longest=longest+1;
if(longest>K){
Str.setCharAt(i, 'L');
minCount=minCount+1;
}
}
if(curr=='L')
longest=0;
}
if(longest < K){
longest=0;int indexoflongest=0;minCount=0;
for(int i=0;i<Str.length();i++){
char curr=S.charAt(i);
if(curr=='M'){
longest=longest+1;
indexoflongest=i;
}
if(curr=='L')
longest=0;
}
Str.setCharAt(indexoflongest, 'M');
minCount=minCount+1;
}
return minCount;
}
There are 2 parts to this algorithm as we want to get the longest character interval equal to K.
We already have a interval >= K so now we need to appropriately change some characters so we greedily change every (k + 1) th character and again start counting from 0.
Now if the interval was less than K I will need to run a sliding window over the array. While running this window I am basically considering converting all L's to M's in this window of length K. But this comes with a side effect of increasing the length of the interval as there could be K's outside so this variable (int nec) keeps track of that. So now I have to also consider converting the 2 possible M's outside the (K length) window to L's.
Here's the complete runnable code in C++. Have a good day.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector <int> vi;
typedef pair<int, int> ii;
int change(string s, int k) {
// handling interval >= k
bool flag = false;
int ans = 0;
int cnt = 0;
for(int i=0; i<s.size(); i++) {
if(s[i] == 'M') cnt++;
else cnt = 0;
if(cnt == k) flag = true;
if(cnt > k) s[i] = 'L', ans++, cnt = 0;
}
if(flag) return ans;
// handling max interval < k
// If the interval is too big.
if(k > s.size()) {
cerr << "Can't do it.\n"; exit(0);
}
// Sliding window
cnt = 0;
for(int i=0; i<k; i++) {
if(s[i] == 'L') cnt++;
}
ans = cnt + (s[k] == 'M'); // new edit
int nec = 0; // new edit
for(int i=k; i<s.size(); i++) {
if(s[i-k] == 'L') cnt--;
if(s[i] == 'L') cnt++;
nec = 0;
if(i-k != 0 && s[i-k-1] == 'M')
nec++;
if(i < s.size()-1 && s[i+1] == 'M')
nec++;
ans = min(ans, cnt + nec);
}
return ans;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
string s;
int k;
cin >> s >> k;
int ans = change(s, k);
cout << ans << "\n";
return 0;
}
int
process_data(const char *m, int k)
{
int m_cnt = 0, c_cnt = 0;
char ch;
const char *st = m;
int inc_cnt = -1;
int dec_cnt = -1;
while((ch = *m++) != 0) {
if (m_cnt++ < k) {
c_cnt += ch == 'M' ? 0 : 1;
if ((m_cnt == k) && (
(inc_cnt == -1) || (inc_cnt > c_cnt))) {
inc_cnt = c_cnt;
}
}
else if (ch == 'M') {
if (*st++ == 'M') {
/*
* losing & gaining M carries no change provided
* there is atleast one L in the chunk. (c_cnt != 0)
* Else it implies stretch of Ms
*/
if (c_cnt <= 0) {
int t;
c_cnt--;
/*
* compute min inserts needed to brak the
* stretch to meet max of k.
*/
t = (k - c_cnt) / (k+1);
dec_cnt += t;
}
}
else {
ASSERT(c_cnt > 0, "expect c_cnt(%d) > 0", c_cnt);
ASSERT(inc_cnt != -1, "expect inc_cnt(%d) != -1", inc_cnt);
/* Losing L and gaining M */
if (--c_cnt < inc_cnt) {
inc_cnt = c_cnt;
}
}
}
else {
if (c_cnt <= 0) {
/*
* take this as a first break and restart
* as any further addition of M should not
* happen. Ignore this L
*/
st = m;
c_cnt = 0;
m_cnt = 0;
}
else if (*st++ == 'M') {
/* losing m & gaining l */
c_cnt++;
}
else {
// losing & gaining L; no change
}
}
}
return dec_cnt != -1 ? dec_cnt : inc_cnt;
}
Corrected code:
int
process_data(const char *m, int k)
{
int m_cnt = 0, c_cnt = 0;
char ch;
const char *st = m;
int inc_cnt = -1;
int dec_cnt = -1;
while((ch = *m++) != 0) {
if (m_cnt++ < k) {
c_cnt += ch == 'M' ? 0 : 1;
if ((m_cnt == k) && (
(inc_cnt == -1) || (inc_cnt > c_cnt))) {
inc_cnt = c_cnt;
}
}
else if (ch == 'M') {
if (*st++ == 'M') {
/*
* losing & gaining M carries no change provided
* there is atleast one L in the chunk. (c_cnt != 0)
* Else it implies stretch of Ms
*/
if (c_cnt <= 0) {
c_cnt--;
}
}
else {
ASSERT(c_cnt > 0, "expect c_cnt(%d) > 0", c_cnt);
ASSERT(inc_cnt != -1, "expect inc_cnt(%d) != -1", inc_cnt);
/* Losing L and gaining M */
if (--c_cnt < inc_cnt) {
inc_cnt = c_cnt;
}
}
}
else {
if (c_cnt <= 0) {
/*
* compute min inserts needed to brak the
* stretch to meet max of k.
*/
dec_cnt += (dec_cnt == -1 ? 1 : 0) + ((k - c_cnt) / (k+1));
/*
* take this as a first break and restart
* as any further addition of M should not
* happen. Ignore this L
*/
st = m;
c_cnt = 0;
m_cnt = 0;
}
else if (*st++ == 'M') {
/* losing m & gaining l */
c_cnt++;
}
else {
// losing & gaining L; no change
}
}
}
if (c_cnt <= 0) {
/*
* compute min inserts needed to brak the
* stretch to meet max of k.
*/
dec_cnt += (dec_cnt == -1 ? 1 : 0) + ((k - c_cnt) / (k+1));
}
return dec_cnt != -1 ? dec_cnt : inc_cnt;
}

making a string samefrom both ends by shifting characters

I am given a string S and I have to make it a palindrome by re-arranging the characters of the given string.
If the given string can not be converted into a palindrome by re-arranging characters, print false and if it is possible to make it a palindrome, print true
My code:
String a=new String(br.readLine()); //given string
int n= a.length();
int j=0,k=n-1,count=0;
boolean flag=false;
for(int i=0;i<n;i++)
{
if(a.charAt(i)=='*')
continue; //for skipping already shifted chars
int ix = a.indexOf(a.charAt(i), i+1);
if(ix >= 0)
{ a=a.substring(0,i+1)+a.substring(i+1, ix) + "*" + a.substring(ix+1);
}
else
{
count++; //number of unique chars which can only be 1 or 0
if(count<=1 && n%2==1)
{
a=a.replaceFirst(a.substring(i,i+1),"*"); //giving middle position to the only unique char at center and replacing it with *
}
else
{
System.out.println("false"); //if more than one unique char, palindrome not possible
flag=true; // shows not possible
break;
}
}
}
if(!flag) // if possible
{
System.out.println("true");
}
One obvious optimization would replace:
if(a.substring(i+1).contains(a.substring(i,i+1)))
{
ans[j++]=i; //storing new positions in ans array
ans[k--]=a.substring(i+1).indexOf(a.charAt(i))+1+i;
a=a.substring(0,i+1)+a.substring(i+1).replaceFirst(a.substring(i,i+1),"*"); //replacing the shifted char with *
}
with:
int ix = a.indexOf(a.charAt(i), i+1);
if(ix >= 0)
{
ans[j++]=i; //storing new positions in ans array
ans[k--]=ix;
a=a.substring(0,i+1)+a.substring(i+1, ix) + "*" + a.substring(ix+1);
}
UPDATE
I wonder if the following code would be faster. There is no indexOf on arrays, so I had to do a loop, but there is no string manipulation:
char[] c = a.toCharArray();
int n= c.length;
int ans[]=new int[n]; // for storing new positions after shifting
int j=0,k=n-1,count=0;
boolean flag=false;
for(int i=0; i < n; i++)
{
char ch = c[i];
if(ch=='*')
continue; //for skipping already shifted chars
int ix = i;
do {
++ix;
} while (ix < n && c[ix] != ch);
if(ix < n)
{
ans[j++]=i;
ans[k--]=ix;
c[ix] = '*';
}
else
{
count++; //number of unique chars which can only be 1 or 0
if(count<=1 && n%2==1)
{
ans[(int)n/2]=i;
c[i] = '*';
}
else
{
System.out.println("-1"); //if more than one unique char, palindrome not possible
flag=true; // shows not possible
break;
}
}
}
UPDATE 2
You can also stop when j has reached n/2:
char[] c = a.toCharArray();
int n= c.length;
int ans[]=new int[n]; // for storing new positions after shifting
int j=0,k=n-1,count=0,half=n/2;
boolean flag=false;
for(int i=0; i < n; i++)
{
char ch = c[i];
if(ch=='*')
continue; //for skipping already shifted chars
int ix = i;
do {
++ix;
} while (ix < n && c[ix] != ch);
if(ix < n)
{
ans[j++]=i;
ans[k--]=ix;
c[ix] = '*';
if (j > half) {
break;
}
}
else
{
count++; //number of unique chars which can only be 1 or 0
if(count<=1 && n%2==1)
{
ans[half]=i;
c[i] = '*';
}
else
{
System.out.println("-1"); //if more than one unique char, palindrome not possible
flag=true; // shows not possible
break;
}
}
}

Double a decimal string

I am writing my own big integer class in java without imports and need a method for doubling a number of any size that is represented by a string. The code I have for this now works, but begins to take a long time once the numbers get bigger and bigger. I essentially create two arrays: the main array and the countdown array which both start as the same thing. Then, I run a while loop and increment the main array up and increment the countdown array down. When the countdown array reaches "0", I terminate the loop and the result is a new array with the new number doubled in size. Then of course I have if statements checking whether the arrays need to change the ten's place, etc.... here's what I have... Is there any way I can make it more efficient and quick?
public static String doubleDecimalString (String main) {
String countdown = main;
String finalBuild = "";
boolean runLoop = true;
//if zero is supplied, skip all the nonsense and just return 0
//else, loop through and find the true double
//was having trobule getting single digits to double correctly so i had to hard code this for now.
if (main.equals("0")) {
return main;
} else if (main.equals("5")) {
return "10";
} else if (main.equals("6")) {
return "12";
} else if (main.equals("7")) {
return "14";
} else if (main.equals("8")) {
return "16";
} else if (main.equals("9")) {
return "18";
} else {
//Array for ORIGINAL NUMBER
int[] mainPiece = new int[main.length()+2];
int arrayLength = mainPiece.length;
for ( int i = 0; i < main.length(); i++ ) {
mainPiece[i+2] = Integer.parseInt(main.substring( i, i+1));
}
mainPiece[0] = -1;
mainPiece[1] = -1;
//Array for COUNTDOWN NUMBER
int[] countdownPiece = new int[main.length()+2];
for ( int i = 0; i < main.length(); i++ ) {
countdownPiece[i+2] = Integer.parseInt(main.substring( i, i+1));
}
countdownPiece[0] = -1;
countdownPiece[1] = -1;
while ( runLoop ) {
//Increment and decrement the two arrays
mainPiece[arrayLength-1] += 1;
countdownPiece[arrayLength-1] -= 1;
//UPDATE MAIN ARRAY
if ( mainPiece[arrayLength-1] == 10 ) {
for (int x = arrayLength-1; x > 0; x--) {
if ( (mainPiece[x] == 10) && (mainPiece[x-1] != 9) ) {
mainPiece[x] = 0;
mainPiece[x -1] += 1;
} else if ( (mainPiece[x] == 10) && (mainPiece[x-1] == 9) ) {
mainPiece[x] = 0;
mainPiece[x -1] += 1;
x = arrayLength;
}
if ( (mainPiece[2] == 10) ) {
mainPiece[1] = 1;
mainPiece[2] = 0;
}
}
} // end main array
//UPDATE SIDE ARRAY
if ( countdownPiece[arrayLength-1] == -1 ) {
for (int x = arrayLength-1; x > 0; x--) {
if ( (countdownPiece[x] == -1) && (countdownPiece[x-1] > 0) && (x > 1) ) {
countdownPiece[x] = 9;
countdownPiece[x -1] -= 1;
} else if ( (countdownPiece[x] == -1) && (countdownPiece[x-1] == 0) && (x > 1) ) {
countdownPiece[x] = 9;
countdownPiece[x -1] -= 1;
x = arrayLength;
}
}
} //end side array
//tests whether the pieces need to be switched to -1 for scanning
for (int x = 0; x < arrayLength - 1; x++) {
if ( (countdownPiece[x] == -1 ) && (countdownPiece[x+1] == 0 ) ) {
countdownPiece[x+1] = -1;
}
}
//if the side array has reached "0" then the loop will stop and the main array will return the new doubled value
if ( (countdownPiece[arrayLength-1] == -1) && (countdownPiece[arrayLength-2] == -1) ) {
break;
}
} //end while loop
//transform array into string
finalBuild = "";
for (int T = 0; T < arrayLength; T++) {
finalBuild += (mainPiece[T] != -1) ? mainPiece[T] : "";
}
return finalBuild;
}
}
How about something like this (it basically does a multiply by two and accounts for carries):
private String doubleNumber(String number)
{
int doubleDig = 0;
int carry = 0;
StringBuilder sb = new StringBuilder();
for (int i = number.length() - 1; i >= 0; --i)
{
char c = number.charAt(i);
int origNum = Character.getNumericValue(c);
doubleDig = origNum * 2 + carry;
carry = doubleDig / 10;
doubleDig = doubleDig % 10;
sb.append(doubleDig);
}
if (carry > 0)
{
sb.append(carry);
}
return sb.reverse().toString();
}
Obviously this only handles integers.
I would use StringBuilder or List to build your doubled value.
Use a carry variable to store the carry amount and initialize to 0.
Start at the least significant digit, double the digits and add the carry.
Then set the carry to digit / 10, then the digit to digit % 10
Append digit to your builder or list.
After you loop through all your digits, check if carry is > 0 and append if needed.
Reverse the StringBuilder or list and join and you have your answer.
public class Doubler {
public static void main(String[] args) {
System.out.println(doubleDec("9123123123087987342348798234298723948723987234982374928374239847239487.23233099"));
}
public static String doubleDec(String dec) {
StringBuilder builder = new StringBuilder();
int carry = 0;
for (int i = dec.length() - 1; i > -1 ; i--) {
char charDigit = dec.charAt(i);
if (charDigit == '.') {
builder.append(charDigit);
} else {
int digit = Character.getNumericValue(charDigit);
if (digit == -1) {
throw new IllegalStateException("Invalid character in decimal string.");
}
digit = digit * 2 + carry;
carry = digit / 10;
digit = digit % 10;
builder.append(digit);
}
}
if (carry != 0) {
builder.append(carry);
}
return builder.reverse().toString();
}
}
// 18246246246175974684697596468597447897447974469964749856748479694478974.46466198

How to count unique characters (only letters and numbers)

// I have a program where I am supposed to count unique characters, only letters and numbers and don't count repeating numbers or letters. However, I have a problem finding out a way for the program not to count spaces and symbols such as "!" "#" "#" "$". So If i type in Hello! I only want the program to say "4", but it says "5" because it counts the exclamation point. Here is my code so far:
public static int countUniqueCharacters(String text1) {
int count = 0;
for (int i = 0; i < text1.length(); i++) {
if (text1.substring(0, i).contains(text1.charAt(i) + ""))
System.out.println();
else
count++;
}
return count;
}
In your else block add a condition that the count will be incremented only if the given character is a letter or a digit.
if (Character.isLetter(text1.charAt(i)) || Character.isDigit(text1.charAt(i))) {
count++;
}
In your example:
public static int countUniqueCharacters(String text1) {
int count = 0;
for (int i = 0; i < text1.length(); i++) {
if (text1.substring(0, i).contains(text1.charAt(i) + "")) {
System.out.println();
} else if (Character.isLetter(text1.charAt(i)) || Character.isDigit(text1.charAt(i))) {
count++;
}
}
return count;
}
here's a sample code written in C# try and understand it. It compares with ascii and adds in a list
string input = Console.ReadLine();//input
List<char> CountedCharacters = new List<char>();
for (int i = 0; i < input.Length; i++)
{ //checking for numerics //checking for alphabets uppercase //checking for alphabets lowercase
if ((input[i] >= 45 && input[i] <= 57) || (input[i] >= 65 && input[i] <= 90) || (input[i] >= 97 && input[i] <= 122))
{
bool AlreadyExists = false;
for (int j = 0; j < CountedCharacters.Count; j++)
{
////checking if already exists
if (CountedCharacters[j]==input[i])
{
AlreadyExists = true;
break;
}
}
////adding in list if doesnt exists
if (!AlreadyExists)
{
CountedCharacters.Add(input[i]);
}
}
}
for (int i = 0; i < CountedCharacters.Count; i++)
{
Console.WriteLine(CountedCharacters[i]);
}
Try this one using regex. You can add and remove the characters you need from the expression to count what you need.
public static int countUniqueCharacters(String text1) {
String newText = text1.replaceAll("[^A-Za-z0-9()\\[\\]]", "");
Set<Character> tempSet = new HashSet<>();
for (char item : newText.toCharArray()) {
tempSet.add(item);
}
return tempSet.size();
}

Cannot read repeating characters

I'm writing a code to read a string and count sets of repeating
public int countRepeatedCharacters()
{
int c = 0;
for (int i = 1; i < word.length() - 1; i++)
{
if (word.charAt(i) == word.charAt(i + 1)) // found a repetition
{
if ( word.charAt(i - 1) != word.charAt(i)) {
c++;
}
}
}
return c;
}
If I try the input
aabbcdaaaabb
I should have 4 sets of repeat decimals
aa | bb | aaaa | bb
and I know I'm not reading the first set aa because my index starts at 1. I tried fixing it around to read zero but then I tr to fix the entire loop to work with the change and I failed, is there any advice as to how to change my index or loop?
Try this code:
public int countRepeatedCharacters(String word)
{
int c = 0;
Character last = null;
bool counted = false;
for (int i = 0; i < word.length(); i++)
{
if (last != null && last.equals(word.charAt(i))) { // same as previous characted
if (!counted) { // if not counted this character yet, count it
c++;
counted = true;
}
}
else { // new char, so update last and reset counted to false
last = word.charAt(i);
counted = false
}
}
return c;
}
Edit - counted aaaa as 4, fixed to count as 1
from what I understood from your question, you want to count number of repeating sets, then this should help.
for (int i = 0; i < word.length()-1; i++){
if (word.charAt(i) == word.charAt(i + 1)){ // found a repetition
if (i==0 || word.charAt(i - 1) != word.charAt(i)) {
c++;
}
}
}
Try this----
public int countRepeatedCharacters()
{
int c = 0,x=0;
boolean charMatched=false;
for (int i = 0; i < word.length(); i++)
{
if(i==word.length()-1)
{
if (word.charAt(i-1) == word.charAt(i))
c++;
break;
}
if (word.charAt(i) == word.charAt(i + 1)) // found a repetition
{
charMatched=true;
continue;
}
if(charMatched==true)
c++;
charMatched=false;
}
return c;
}
Try this method. It counts the sets of repeating charactors.
public static void main(String[] args) {
String word = "aabbcdaaaabbc";
int c = 0;
for (int i = 0; i < word.length()-1; i++) {
// found a repetition
if (word.charAt(i) == word.charAt(i + 1)) {
int k = 0;
while((i + k + 1) < word.length()) {
if(word.charAt(i+k) == word.charAt(i + k + 1)) {
k++;
continue;
}
else {
break;
}
}
c++;
i+=k-1;
}
}
System.out.println(c);
}
You can try something like this:-
public static void main(String str[]) {
String word = "aabbcdaaaabbc";
int c = 1;
for (int i = 0; i < word.length() - 1; i++) {
if (word.charAt(i) == word.charAt(i + 1)) {
c++;
} else {
System.out.println(word.charAt(i)+ " = " +c);
c = 1;
}
}
System.out.println(word.charAt(word.length()-1)+ " = " +c);
}
You can modify this as per your needs, by removing the sysouts and other stuffs.
Using length() -1 is causing you to not consider the last character in your calculations.
This is causing you to lose the last repetitive character.
Finally, I would have done this as follows:
public static int countRepeatedCharacters(String word)
{
boolean withinRepeating = false;
int c = 0;
for (int i = 1; i < word.length(); i++)
{
if (!withinRepeating && (withinRepeating = word.charAt(i) == word.charAt(i - 1)))
c++;
else
withinRepeating = word.charAt(i) == word.charAt(i - 1);
}
return c;
}

Categories

Resources