I have a String (lowercase letters) of size N with 1 based index.
Now I am given Q queries and each query consists of two integers x,y.
For every query I have to print min number of deletion from substring(x,y) (x,y included) such that substring has same frequency of distinct characters.
For example: consider a query which forms the substring abbccd,
now min no. of deletions in it are 2(1b,1c).
1<= N,Q <= 10^5
1<=X<=Y<=N
I tried the brute force approach where for every query I calculated frequency of characters and then calculated deletion by equating all frequencies to min frequency.
But I know that this approach is wrong and will also result in TLE. Can anyone help me with it.
My code:
import java.util.Arrays;
import java.util.Scanner;
public class q1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int q = in.nextInt();
in.nextLine();
String s = in.nextLine();
int x,y;
while(q>0){
x = in.nextInt();
y = in.nextInt();
String temp = s.substring(x-1, y);
char c[] = temp.toCharArray();
int count[] = new int[26];
//calculating the frequencies.
for (int i = 0; i < c.length; i++) {
count[c[i]-'a']++;
}
int min = Integer.MAX_VALUE;
for (int i = 0; i < count.length; i++) {
if(count[i]!=0 && count[i]<min){
min = count[i];
}
}
int deletions = 0;
for (int i = 0; i < count.length; i++) {
if(count[i]!=0){
deletions += (count[i]-min);
}
}
System.out.println(deletions);
q--;
}
}
}
Problem Link
Here is my solution with O(26*26) steps per query.
Made a cumulative frequency array to store the frequency of every character up-til the "ith" position in the string.
dp[i][0] is the frequency of "a" in the string from the index 1 to i inclusive.
dp[i][1] is the frequency of "b" in the string from the index 1 to i inclusive.
and so on up-til 25 for "z".
Now in every query we can calculate the frequency of every character in the sub-string x to y, by subtracting frequency of a character "i" up-til "x-1" from the frequency of the same character up-til "y" i.e.
freq[i] = dp[x-1][i] - dp[y][i];
Now once we have the frequency of every character in the sub-string we can iterate over these frequencies and calculate the number of deletions for every unique character.
For example if we have a sub-string "ddddbbacc"
freq of "a" is 1
freq of "b" is 2
freq of "c" is 2
freq of "d" is 4
frequencies = [1, 2, 2, 4]
at first iteration we try to make all the frequencies equal to freq[0] i.e 1.
to do so we delete one char from the characters having freq = 2 and 3 characters from the character having freq = 4.
this gives us a answer of 1+1+3 = 5.
In second iteration we try to make all the frequencies equal to freq[1] i.e 2.
to do so we delete 3 characters from the character having freq = 4.
and we also delete all the characters whose freq < 2
this gives us a answer of 1+2 = 3.
In worst case it takes 26*26 steps per query.
Found the question
here
import java.util.Arrays;
import java.util.Scanner;
import java.util.Collections;
import java.util.ArrayList;
class q1 {
static int[][] dp = new int[100005][27];
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int q = in.nextInt();
in.nextLine();
String s = in.nextLine();
for (int i = 0; i < s.length(); i++){ //O(N*26)
for (int j = 0; j < 26; j++)
dp[i+1][j] = dp[i][j];
dp[i+1][(int)(s.charAt(i))-(int)('a')]++;
}
int x,y;
while(q>0){ //O(Q*700)
x = in.nextInt();
y = in.nextInt();
int freq[] = new int[27];
for(int i = 0; i < 26; i++) //O(1)
freq[i] = dp[y][i] - dp[x-1][i];
ArrayList<Integer> f = new ArrayList<Integer>();
for(int i = 0; i < 26; i++) //O(1)
if(freq[i] != 0)
f.add(freq[i]);
Collections.sort(f); //O(26*log26)
int ans = s.length() + 1;
int drop = 0;
for(int i = 0; i < f.size(); i++){ //O(26*26)
int currans = drop;
for(int j = i+1; j < f.size(); j++)
currans += (f.get(j)-f.get(i));
if (ans > currans)
ans = currans;
drop += f.get(i);
}
if (drop < ans)
ans = drop;
System.out.println(ans);
q--;
}
}
}
Related
I'm very new to coding.
I'm writing this code and I'm struggling because I need to make a code that makes an array with 8 random integers and then it swaps the largest integer with the first number in the array.
When doing this though I'm getting an error and I cannot seem to fix it.
import java.util.Scanner;
import java.util.Random;
public class finalExam {
public static void main(String []args) {
Scanner input = new Scanner(System.in);
Random spinner = new Random();
int [] userInputs = new int [8];
for (int i = 0; i < userInputs.length; i++) {
userInputs[i] = spinner.nextInt(100)+1;
System.out.println(userInputs[i]);
}
int largest = userInputs[0];
for(int j = 1; j < userInputs.length; j++) {
if(userInputs[j] > largest)
largest = userInputs[j];
}
System.out.println("Your largest number is: " + largest);
int holder;
int [] arr = new int[101];
for (int m = 0; m <= arr.length; m++) {
holder = largest;
userInputs[0] = userInputs[largest];
holder = userInputs[0];
}
}
}
The error comes from the last bit of your code. userInputs[largest] is out of bound because the array is only 8 integers long (while largest can have a value of 100).
Since you need the position of the largest number, you'll have to save it in largestPosition when you identify which number is the largest, like so:
int largest = userInputs[0];
int largestPosition = 0;
for(int j = 1; j < userInputs.length; j++) {
if(userInputs[j] > largest){
largest = userInputs[j];
largestPosition = j;
}
}
That said, the loop which you used at the end also isn't needed here. You could just swap the first value of the array with the largest one using this method:
int first = userInputs[0];
userInputs[0] = largest;
userInputs[largestPosition] = first;
What is the mistake in my code?
Given a string consisting of lowercase letters, arrange all its letters in ascending order.
Input: The first line of the input contains T, denoting number of testcases. Then follows description of each testcase. The first line of the testcase contains positive integer N denoting the length of string. The second line contains the string.
Output: For each testcase, output the sorted string.
Constraints:
1 <= T <= 100
1 <= N <= 100
import java.util.*;
class GFG {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for (int i = 1; i <= t; i++) {
int n = sc.nextInt();
sc.nextLine();
String S = sc.nextLine();
String sor = "";
for (int j = 0; j < n; j++) {
int min = j;
for (int k = j + 1; k < n; k++) {
if (S.charAt(k) > S.charAt(min)) {
min = k;
}
}
sor += S.substring(min, min + 1);
}
System.out.println(sor);
}
}
}
For Input:
1
5
edcab
Output:
edcbb
Expected Output:
abcde
import java.util.*;
class GFG {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for (int i = 1; i <= t; i++) {
int n = sc.nextInt();
sc.nextLine();
String S = sc.nextLine();
System.out.println("S: "+S);
String sor = "";
for (int j = 0; n > 0; j++) {
int min = 0;
for (int k = 0; k < n; k++) {
if (S.charAt(k) < S.charAt(min)) {
min = k;
}
}
sor += S.substring(min, min + 1);
S = S.substring(0, min) + S.substring(min + 1);
n--;
}
System.out.println(sor);
}
}
}
This code does what you want. I changed > to < and I removed every char that added to sorted String from unsorted String. This way we don't need to deal with the same char again and again.
You are not exchanging the place of the min character after finding it. But Strings in java are immutable so you can't swap the places of characters in it. I suggest you convert your String to a char[] so that you can swap the characters:
public static void main (String[] args){
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for(int i=1; i<=t; i++){
int n = sc.nextInt();
sc.nextLine();
String S = sc.nextLine().toCharArray(); // convert it to char array
char[] sor = new char[S.length];
for(int j=0; j<n; j++){
int min = j;
for(int k =j+1; k<n; k++){
if(S[k]<S[min]){
min = k;
}
}
swap(S, min, j);
sor[j] = S[min]
}
System.out.println(new String(sor));// reconvert to string
}
}
public static void swap(char[] c,int x,int y){
char temp= c[x];
c[x] = c[y];
c[y] = temp;
}
You can use String.toCharArray method to iterate over the array of characters char[] of this string, sort their decimal values and return back the string that contains the characters of the sorted array:
public static void main(String[] args) {
String str = "edcab";
String sorted = selectionSort(str.toCharArray());
System.out.println(sorted); // abcde
}
public static String selectionSort(char[] arr) {
// iterate over all subsets of the array
// (0-last, 1-last, 2-last, 3-last, ...)
for (int i = 0; i < arr.length; i++) {
// assume the min is
// the first element
char min = arr[i];
// index of the
// min element
int min_i = i;
// check the elements
// after i to find
// the smallest
for (int j = i + 1; j < arr.length; j++) {
// if this element
// is less, then it
// is the new min
if (arr[j] < min) {
min = arr[j];
min_i = j;
}
}
// if min element is not
// equal to the current
// one, then swap them
if (i != min_i) {
char temp = arr[i];
arr[i] = arr[min_i];
arr[min_i] = temp;
}
}
return String.valueOf(arr);
}
You can use String.codePoints method to iterate over int values of the characters of this string, sort them and collect another sorted string:
String str = "edcab";
String sorted = str.codePoints()
.sorted()
.mapToObj(Character::toString)
.collect(Collectors.joining());
System.out.println(sorted); // abcde
See also:
• How do I not take Special Characters in my Password Validation (without Regex)?
• Java Selection Sort
I have just started my java course so still cannot understand a lot of things, help me out please.
So here is the base code
import java.util.Arrays;
import java.util.Scanner;
public class Main<i> {
public static void main(String[] args ) {
System.out.println (" Enter count of digits: ");
Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
int [] sourceNumber = new int [size];
System.out.println("Enter your digits with space");
for (int i = 0; i < size; i++) {
sourceNumber[i] = scanner.nextInt();
[...]
So I have no single idea how to make method to find any count with stepful numbers. Example:
I have counts like: 12405346 534952359 6456934 1234567
so I need system to find 1234567 and print it out
For example I made method to find a count with munimum same numbers like this:
[...]
for (int j = 0; j < 10; j++) {
if (digitsCount[j] > 0)
differentDigitsCount++;
}
mindifferent = differentDigitsCount;
for (int k = 1; k < size; k++) {
int differentDigitsCount1 = 0;
int[] digitsCount1 = new int[10];
while (sourceNumber[k] != 0) {
digitsCount1[(int) (sourceNumber[k] % 10)]++;
sourceNumber[k] /= 10;
}
for (int j = 0; j < 10; j++) {
if (digitsCount1[j] > 0)
differentDigitsCount1++;
}
if (mindifferent <= differentDigitsCount1) {
} else {
mindifferent = differentDigitsCount1;
l = k;
}
}
System.out.println("Digit with minimum same numbers: " + moimassiv[l]);
[...]
This code is huge, but its fine for me now. I just need to make method to find stepful counts
I'm assuming that you want to print those numbers whose digits are sorted from smallest to largest. Is that right?
You can convert the number to String, then you can get each digit by using charAt(int index) method
You can iterate over sourceNumber and call hasSortedNumbers() for each one to know if its digits are sorted.
for (int number : sourceNumber) {
String valueOfNumber = String.valueOf(number);
if (hasSortedNumbers(valueOfNumber)) {
System.out.println(number);
}
}
This is the code for hasSortedNumbers()
public static boolean hasSortedNumbers(String valueOfNumber) {
for (int i = 0; i < valueOfNumber.length() - 1; i++) {
if (valueOfNumber.charAt(i) >= valueOfNumber.charAt(i + 1)) {
return false;
}
}
return true;
}
I'm assuming you're going to use this method from main, so it needs to be static, since main is static.
Basically I'm comparing each digit with the next one, if it turns out that the next one is smaller, it returns false. If not, when it exits the for loop, it returns true.
This Question is part of ongoing Competition , I have solved the 75% of this Question Data Set but the 25% is giving me TLE. I am asking why it's is giving TLE an i am sure my complexity is O(n*n)Question:
String S consisting of N lowercase English alphabets. We has prepared a list L consisting of all non empty substrings of the string S.
Now he asks you Q questions. To ith question, you need to count the number of ways to choose exactly Ki equal strings from the list L
For Example:
String = ababa
L = {"a", "b", "a", "b", "a", "ab", "ba", "ab", "ba", "aba", "bab", "aba", "abab", "baba", "ababa"}.
k1 = 2: There are seven ways to choose two equal strings ("a", "a"), ("a", "a"), ("a", "a"), ("b", "b"), ("ab", "ab"), ("ba", "ba"), ("aba", "aba").
k2 = 1: We can choose any string from L (15 ways).
k3 = 3: There is one way to choose three equal strings - ("a", "a", "a").
k4 = 4: There are no four equal strings in L .
Question LINK
My approach
I am making a TRIE of IT and Calculating The and Array F[i] where F[i] represent the number of times i equal String Occur.
My TRIE:
static class Batman{
int value;
Batman[] next = new Batman[26];
public Batman(int value){
this.value = value;
}
}
MY Insert Function
public static void Insert(String S,int[] F , int start){
Batman temp = Root;
for(int i=start;i<S.length();i++){
int index = S.charAt(i)-'a';
if(temp.next[index]==null){
temp.next[index] = new Batman(1);
F[1]+=1;
}else{
temp.next[index].value+=1;
int xx = temp.next[index].value;
F[xx-1]-=1;
F[xx]+=1;
// Calculating The Frequency of I equal Strings
}
temp = temp.next[index];
}
}
MY MAIN FUNCTION
public static void main(String args[] ) throws java.lang.Exception {
Root = new Batman(0);
int n = in.nextInt();
int Q = in.nextInt();
String S = in.next();
int[] F = new int[n+1];
for(int i=0;i<n;i++)
Insert(S,F,i);
long[] ans = new long[n+1];
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
ans[i]+= F[j]*C[j][i]; // C[n][k] is the Binomial Coffecient
ans[i]%=mod;
}
}
while(Q>0){
Q--;
int cc = in.nextInt();
long o =0;
if(cc<=n) o=ans[cc];
System.out.println(o+" "+S.length());
}
}
Why My appraoch is giving TLE as time Complexity is O(N*N) ans the length of String is N<=5000. Please Help me Working CODE
One reason this program get TLE (keep in mind that time constraint is 1 sec):
Each time you create a Batman object, it will create an array with length [26], and it is equivalence to adding a loop with n = 26.
So, you time complexity is 26*5000*5000 = 650000000 = 6.5*10^8 operations, theoretically, it can still fit into time limit if CPU speed is 10^9 operations per sec, but also keep in mind that there are some heavy calculation stuffs after this, so, this should be the reason.
To solve this problem, I used Z-algorithm and get accepted: Link
The actual code is quite complex, so the idea is, you have a table count[i][j], which is the number of substring that matched substring (i, j). Using Z-algorithm, you can have a time complexity of O(n^2).
For each string s:
int n = in.nextInt();
int q = in.nextInt();
String s = in.next();
int[][] cur = new int[n][];
int[][] count = new int[n][n];
int[] length = new int[n];
for (int i = 0; i < n; i++) {
cur[i] = Z(s.substring(i).toCharArray());//Applying Z algorithm
for (int j = 1; j < cur[i].length; j++) {
if (cur[i][j] > length[j + i]) {
for (int k = i + length[j + i]; k < i + cur[i][j]; k++) {
count[i][k]++;
}
length[j + i] = cur[i][j];
}
}
}
int[] F = new int[n + 1];
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
int v = count[i][j] + (length[i] < (j - i + 1) ? 1 : 0);
F[v]++;
}
}
Z-algorithm method:
public static int[] Z(char[] s) {
int[] z = new int[s.length];
int n = s.length;
int L = 0, R = 0;
for (int i = 1; i < n; i++) {
if (i > R) {
L = R = i;
while (R < n && s[R - L] == s[R])
R++;
z[i] = R - L;
R--;
} else {
int k = i - L;
if (z[k] < R - i + 1) {
z[i] = z[k];
} else {
L = i;
while (R < n && s[R - L] == s[R])
R++;
z[i] = R - L;
R--;
}
}
}
return z;
}
Actual code: http://ideone.com/5GYWeS
Explanation:
First, we have an array length, with length[i] is the longest substring that matched with the string start from index i
For each index i, after calculate the Z function, we see that, if cur[i][j] > length[j + i], which means, there exists one substring longer than previous substring matched at index j + i, and we havent counted them in our result, so we need to count them.
So, even there are 3 nested for loop, but each substring is only counted once, which make this whole time complexity is O(n ^2)
for (int j = 1; j < cur[i].length; j++) {
if (cur[i][j] > length[j + i]) {
for (int k = i + length[j + i]; k < i + cur[i][j]; k++) {
count[i][k]++;
}
length[j + i] = cur[i][j];
}
}
For below loop, we notice that, if there is a matched for substring (i,j), length[i] >= length of substring (i,j), but if there is no matched, we need to add 1 to count substring (i,j), as this substring is unique.
for(int j = i; j < n; j++){
int v = count[i][j] + (length[i] < (j - i + 1) ? 1 : 0);
F[v]++;
}
I'm trying to resolve all the combinations of elements based on a given string.
The string is like this :
String result="1,2,3,###4,5,###6,###7,8,";
The number of element between ### (separated with ,) is not determined and the number of "list" (part separated with ###) is not determined either.
NB : I use number in this example but it can be String too.
And the expected result in this case is a string containing :
String result = "1467, 1468, 1567, 1568, 2467, 2468, 2567, 2568, 3467, 3468, 3567, 3568"
So as you can see the elements in result must start with an element of the first list then the second element must be an element of the second list etc...
From now I made this algorithm that works but it's slow :
String [] parts = result.split("###");
if(parts.length>1){
result="";
String stack="";
int i;
String [] elmts2=null;
String [] elmts = parts[0].split(",");
for(String elmt : elmts){ //Browse root elements
if(elmt.trim().isEmpty())continue;
/**
* This array is used to store the next index to use for each row.
*/
int [] elmtIdxInPart= new int[parts.length];
//Loop until the root element index change.
while(elmtIdxInPart[0]==0){
stack=elmt;
//Add to the stack an element of each row, chosen by index (elmtIdxInPart)
for(i=1 ; i<parts.length;i++){
if(parts[i].trim().isEmpty() || parts[i].trim().equals(","))continue;
String part = parts[i];
elmts2 = part.split(",");
stack+=elmts2[elmtIdxInPart[i]];
}
//rollback i to previous used index
i--;
if(elmts2 == null){
elmtIdxInPart[0]=elmtIdxInPart[0]+1;
}
//Check if all elements in the row have been used.
else if(elmtIdxInPart[i]+1 >=elmts2.length || elmts2[elmtIdxInPart[i]+1].isEmpty()){
//Make evolve previous row that still have unused index
int j=1;
while(elmtIdxInPart[i-j]+1 >=parts[i-j].split(",").length ||
parts[i-j].split(",")[elmtIdxInPart[i-j]+1].isEmpty()){
if(j+1>i)break;
j++;
}
int next = elmtIdxInPart[i-j]+1;
//Init the next row to 0.
for(int k = (i-j)+1 ; k <elmtIdxInPart.length ; k++){
elmtIdxInPart[k]=0;
}
elmtIdxInPart[i-j]=next;
}
else{
//Make evolve index in current row, init the next row to 0.
int next = elmtIdxInPart[i]+1;
for(int k = (i+1) ; k <elmtIdxInPart.length ; k++){
elmtIdxInPart[k]=0;
}
elmtIdxInPart[i]=next;
}
//Store full stack
result+=stack+",";
}
}
}
else{
result=parts[0];
}
I'm looking for a more performant algorithm if it's possible. I made it from scratch without thinking about any mathematical algorithm. So I think I made a tricky/slow algo and it can be improved.
Thanks for your suggestions and thanks for trying to understand what I've done :)
EDIT
Using Svinja proposition it divide execution time by 2:
StringBuilder res = new StringBuilder();
String input = "1,2,3,###4,5,###6,###7,8,";
String[] lists = input.split("###");
int N = lists.length;
int[] length = new int[N];
int[] indices = new int[N];
String[][] element = new String[N][];
for (int i = 0; i < N; i++){
element[i] = lists[i].split(",");
length[i] = element[i].length;
}
// solve
while (true)
{
// output current element
for (int i = 0; i < N; i++){
res.append(element[i][indices[i]]);
}
res.append(",");
// calculate next element
int ind = N - 1;
for (; ind >= 0; ind--)
if (indices[ind] < length[ind] - 1) break;
if (ind == -1) break;
indices[ind]++;
for (ind++; ind < N; ind++) indices[ind] = 0;
}
System.out.println(res);
This is my solution. It's in C# but you should be able to understand it (the important part is the "calculate next element" section):
static void Main(string[] args)
{
// parse the input, this can probably be done more efficiently
string input = "1,2,3,###4,5,###6,###7,8,";
string[] lists = input.Replace("###", "#").Split('#');
int N = lists.Length;
int[] length = new int[N];
int[] indices = new int[N];
for (int i = 0; i < N; i++)
length[i] = lists[i].Split(',').Length - 1;
string[][] element = new string[N][];
for (int i = 0; i < N; i++)
{
string[] list = lists[i].Split(',');
element[i] = new string[length[i]];
for (int j = 0; j < length[i]; j++)
element[i][j] = list[j];
}
// solve
while (true)
{
// output current element
for (int i = 0; i < N; i++) Console.Write(element[i][indices[i]]);
Console.WriteLine(" ");
// calculate next element
int ind = N - 1;
for (; ind >= 0; ind--)
if (indices[ind] < length[ind] - 1) break;
if (ind == -1) break;
indices[ind]++;
for (ind++; ind < N; ind++) indices[ind] = 0;
}
}
Seems kind of similar to your solution. Does this really have bad performance? Seems to me that this is clearly optimal, as the complexity is linear with the size of the output, which is always optimal.
edit: by "similar" I mean that you also seem to do the counting with indexes thing. Your code is too complicated for me to go into after work. :D
My index adjustment works very simply: starting from the right, find the first index we can increase without overflowing, increase it by one, and set all the indexes to its right (if any) to 0. It's basically counting in a number system where each digit is in a different base. Once we can't even increase the first index any more (which means we can't increase any, as we started checking from the right), we're done.
Here is a somewhat different approach:
static void Main(string[] args)
{
string input = "1,2,3,###4,5,###6,###7,8,";
string[] lists = input.Replace("###", "#").Split('#');
int N = lists.Length;
int[] length = new int[N];
string[][] element = new string[N][];
int outCount = 1;
// get each string for each position
for (int i = 0; i < N; i++)
{
string list = lists[i];
// fix the extra comma at the end
if (list.Substring(list.Length - 1, 1) == ",")
list = list.Substring(0, list.Length - 1);
string[] strings = list.Split(',');
element[i] = strings;
length[i] = strings.Length;
outCount *= length[i];
}
// prepare the output array
string[] outstr = new string[outCount];
// produce all of the individual output strings
string[] position = new string[N];
for (int j = 0; j < outCount; j++)
{
// working value of j:
int k = j;
for (int i = 0; i < N; i++)
{
int c = length[i];
int q = k / c;
int r = k - (q * c);
k = q;
position[i] = element[i][r];
}
// combine the chars
outstr[j] = string.Join("", position);
}
// join all of the strings together
//(note: joining them all at once is much faster than doing it
//incrementally, if a mass concatenate facility is available
string result = string.Join(", ", outstr);
Console.Write(result);
}
I am not a Java programmer either, so I adapted Svinja's c# answer to my algorithm, assuming that you can convert it to Java also. (thanks to Svinja..)