I need to write an answer with the least complexity degree. My questions is regarding nested-loops that do not always run. I have a for loops that iterates N times, depending on length of the string, and searches for a 'char' value. When it finds it, it iterates the loop again from this point onwards, looking for more 'char' values.
I wrote the following method:
public static int subStrMaxC(String s, char c, int k) {
char[] stringChars=new char[s.length()];
//System.out.print("the string of the characters is");
for(int i=0;i<stringChars.length;i++) {
stringChars[i]=s.charAt(i);
// System.out.print(stringChars[i]);
}
int count=0;
int bigcount=0;
int[] charArray=new int[s.length()];
for(int i=0;i<stringChars.length;i++) {
count=0;
if(stringChars[i]=='c') {
count++;
for(int j=i+1;j<stringChars.length;j++) {
if(stringChars[j]=='c') {
count++;
if((count>=2)&&(count<=k+2)) {
bigcount++;
if(count==k+2) {
count=0;
j=stringChars.length-1;
}
}
}
}
}
}
return bigcount;
}
Since the second loop do not iterate unless the first loop finds a value that meets the condition, I did not know whether the complexity is defined O(n^2)-which is my assumption, as the second loop can, in the worst case run N*(N-i) times- or just O(n), which is what I'm looking for.
Thank you!
I am quite sure this is the best you can do, but of course I may be wrong. The problem you have with your approach is your limited use of Space Complexity. With the approach below, you iterate through the string only once (i.e. no 'j' loop which leads to the n squared problem). Here you build out candidate substrings by using space/memory. Now you only have to iterate over candidate substrings which has a much lower time complexity than your first approach.
public class MaxKSubstring {
public static void main(String[] args) {
String INPUT = "testingwithtees";
char C = 't';
int K = 1;
int count = subStrMaxC(INPUT, C, K);
System.out.println(count);
}
public static int subStrMaxC(String s, char c, int k) {
char letters[] = s.toCharArray();
int valid = 0;
List<Candidate> candidates = new ArrayList<Candidate>();
for (int i=0; i< s.length(); i++) {
if (letters[i] == c)
candidates.add(new Candidate(k, c));
for (Candidate candidate : candidates) {
if (candidate.addLetter(letters[i])) {
System.out.println(candidate.value);
valid++;
}
}
}
return valid;
}
}
class Candidate {
final int K;
final char C;
public Candidate(int k, char c) {
super();
K = k;
C = c;
}
boolean endsWithC = false;
String value = "";
int kValue = 0;
public boolean addLetter(char letter) {
endsWithC = false;
value = value+letter;
if (letter == C) {
kValue++;
endsWithC = true;
}
return endsWithC && kValue <= K+2 && value.length() > 1;
}
}
O(n) best case,
O(n2) worst case
I'm not sure what you mean by the least complexity. If you are referring to the best case, that would be O(n) performance. (The parent loop iterates only and the nested loops are never iterated) since the matching case:
if(stringChars[i]=='c')
Is always false. However, the worst case time complexity which is usually what we're referring to is O(n2), owing to the fact that the condition if(stringChars[i]=='c') returns true every single time.
Related
I have tried out 387.First Unique Character In A string
Given a string s, find the first non-repeating character in it and
return its index. If it does not exist, return -1.
EXAMPLE : 1
Input: s = "leetcode"
Output: 0
EXAMPLE :2
Input: s = "loveleetcode"
Output: 2
I have been trying this problem. I thought we will pick one by one all the characters and check if a repeating character exists break from the loop. And if not then return that index.I have thought over a solution which I believe is not the most efficient way but I want to know the how can I solve this problem with the approach given below:
public int firstUniqChar(String s) {
for(int i=0;i<s.length();i++){
for(int j=i+1;j<s.length();j++){
if(s.charAt(i)==s.charAt(j)){
break;
}
}
}
return -1;
}
I'm confused how to return the index.I'm unable to find the logic after:
for(int j=i+1;j<s.length();j++){
if(s.charAt(i)==s.charAt(j)){
break;
}
}
If anyone can help me find out the logic here.
Try this.
public static int firstUniqChar(String s) {
L: for (int i = 0, length = s.length(); i < length; i++) {
for (int j = 0; j < length; j++)
if (i != j && s.charAt(i) == s.charAt(j))
continue L;
return i;
}
return -1;
}
public static void main(String[] args) {
System.out.println(firstUniqChar("leetcode"));
System.out.println(firstUniqChar("loveleetcode"));
System.out.println(firstUniqChar("aabb"));
}
output:
0
2
-1
you can use a flag variable.
public int firstUniqChar(String s) {
int flag=0;
for(int i=0;i<s.length();i++){
flag=0;
for(int j=0;j<s.length();j++){
if(s.charAt(i)==s.charAt(j) && i!=j){
flag=1;
break;
}
}
if(flag==0){
return i;
}
}
return -1;
}
There are 26 possible lowercase English letters, so you could use two 26 element arrays.
One array, letterCount, keeps counts of each letter. Start at 0 and add 1 every time the corresponding letter appears in the text string. The second array, position, holds the position of the first occurrence of that letter, or -1 if the letter never appears. You will need to initialise that array to -1 for all elements.
Process the string in order, recording initial positions, once only for each letter, and incrementing the count for each letter in the string.
After the string has been processed, look through the letterCount array. If there are no letters with a 1 count then return -1. If exactly one letter has a 1 count, then return the position of that letter from the position array. If more than one letter has a 1 count, then pick the one with the lowest value for its position.
Using two loops is a highly inefficient way of solving this problem. The string can be up to 100,000 characters long and you are processing it multiple times. Far better to process it only once, keeping track of what you have found so far.
Fix you code
You need to add a variable that tells you if you have breaked the loop or not
static int firstUniqChar(String s) {
boolean duplicate;
for (int i = 0; i < s.length(); i++) {
duplicate = false;
for (int j = i + 1; j < s.length(); j++) {
if (s.charAt(i) == s.charAt(j)) {
duplicate = true;
break;
}
}
if (!duplicate) {
return i;
}
}
return -1;
}
Improve
There is a smarter way, that is finding the last index occurence of the current char, if it's equal to the current index : that char is unique and you return its index
static int firstUniqChar(String s) {
for (int i = 0; i < s.length(); i++) {
if (s.lastIndexOf(s.charAt(i)) == i) {
return i;
}
}
return -1;
}
If you do not bother about time complexity using IdenxOF operations, then one can try this solution.
indexOf() – also runs in linear time. It iterates through the internal array and checking each element one by one. So the time
complexity for this operation always requires O(n) time.
int firstUniqCharOneLoop(String str) {
for (int i = 0; i < str.length(); i++) {
if (str.indexOf(str.charAt(i))== str.lastIndexOf(str.charAt(i)) ) {
return i;
}
}
return -1;
}
The lowest complexity I managed to achieve:
public class UniqueSymbolFinder {
static int findFirstUniqueChar(String s) {
Set<Character> set = new HashSet<>(s.length());
List<CharWithIndex> candidates = new LinkedList<>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
CharWithIndex charWithIndex = new CharWithIndex(ch, i);
if (set.add(ch)) {
candidates.add(charWithIndex);
} else {
candidates.remove(charWithIndex);
}
}
return candidates.size() == 0 ? -1 : candidates.get(0).index;
}
/**
* Class for storing the index.
* Used to avoid of using an indexOf or other iterations.
*/
private static class CharWithIndex {
int index;
char ch;
private CharWithIndex(char ch, int index) {
this.ch = ch;
this.index = index;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CharWithIndex that = (CharWithIndex) o;
return ch == that.ch;
}
#Override
public int hashCode() {
return Objects.hash(ch);
}
}
}
I believe the memory usage can still be optimized.
100% Correct JAVA Solution
Since the question is about returning the index of the first non-repeating character in a string, we need some data structure to save the index of each character in the string for us.
I choose here the HashMap of Java. Basically, what you can do with it, you can save a pair of values (or pair of other data structures).
So, in my solution, I am saving a Character Integer pair. The first is considered as a key (here it is each character in the string), and the second is its index value.
The problem here is that we only want to keep the minimum index of non-repeating characters and that's why if you take a look below, you will find the maxIndexForRepeatedValues is set to be 10 power 5 as the input constraint says 1 <= s.length <= 10 power 5.
However, I am using that value to neglect repeated characters that would be found in the HashMap and at the end, we retrieve the minimum index which is the index of course for the first character from the map, or if there were only repeated characters, we return -1.
To make the code shorter, I used ternary-operator but you can write it with if-else if you want!
class Solution {
public int firstUniqChar(String s) {
int maxIndexForRepeatedValues = 100000;
Map<Character, Integer> map = new HashMap<>();
for (int i = 0 ; i < s.length() ; i++) {
char key = s.charAt(i);
int resIndex = map.containsKey(key) ? maxIndexForRepeatedValues : i;
map.put(key, resIndex);
}
int minIndex = Collections.min(map.values());
return minIndex == maxIndexForRepeatedValues ? -1 : minIndex;
}
}
I need to build each combination of length L from an String Array/ArrayList, where L is greater than the Array length
I currently have a recursive method (not of my own creation) that will generate each combination of a String[], as long as the combinations are shorter than the Array.
example/psudoCode:
input (2, {A,B,C})
returns {AA, AB, AC, BA, BC, CB, CA}
As of now, if the requested combination length (2 in the example) is greater than the Array length (4,5,6... instead of 2), the recursive method shoots out that sweet sweet ArrayIndexOutOfBounds error.
What I need is a method (recursive or not) that will return every combination of the array, regardless of whether the combinations are longer than the Array itself. Would this be done better by adding more letters to the Array and crossing my fingers or is there a legitimate way to accomplish this? Thank you!
Here is the method I have been using. If u know where the credit lies please say so, this is not of my own creation.
public class bizzBam
{
// Driver method to test below methods
public static void main(String[] args) {
System.out.println("First Test");
String set1[] = {"a", "b","c"};
printAllKLength(set1, pointX);
}
// The method that prints all possible strings of length k. It is
// mainly a wrapper over recursive function printAllKLengthRec()
static void printAllKLength(String set[], int k) {
int n = set.length+2;
printAllKLengthRec(set, "", n, k);
}
// The main recursive method to print all possible strings of length k
static void printAllKLengthRec(String set[], String prefix, int n, int length) {
// Base case: k is 0, print prefix
if (length == 0) {
System.out.println(prefix);
return;
}
// One by one add all characters from set and recursively
// call for k equals to k-1
for (int i = 0; i < n; ++i) {
// Next character of input added
String newPrefix = prefix + set[i];
// k is decreased, because we have added a new character
printAllKLengthRec(set, newPrefix, n, length - 1);
}
}
}
(Edit forgot to say:)
For this algorithim at least, if "PointX" is greater than the input array's length, it will return the indexoutofbounds.
Strictly speaking these are permutations rather than combinations. You're generating all permutations of k elements selected from a set of n candidates, with replacement (or repitition). There will be n^k such permutations.
Here's a non-recursive solution.
public class Permutations
{
public static void main(String[] args)
{
permutationsKN(new String[]{"a", "b", "c"}, 4);
}
static void permutationsKN(String[] arr, int k)
{
int n = arr.length;
int[] idx = new int[k];
String[] perm = new String[k];
while (true)
{
for(int i=0; i<k; i++) perm[i] = arr[idx[i]];
System.out.println(String.join("", perm));
// generate the next permutation
int i = idx.length - 1;
for (; i >= 0; i--)
{
idx[i]++;
if (idx[i] < n) break;
idx[i] = 0;
}
// if the first index wrapped around then we're done
if (i < 0) break;
}
}
}
You have two problems here:
int n = set.length+2; -> This is giving you your "sweet sweet" IndexArrayOutOfBoundsException. Change it to set.length-1. I am not sure why you decided to randomnly put +2 there.
for (int i = 0; i < n; ++i) -> You will be looping from 0 to n. You need to loop from 0 to n-1.
Edit: Or as #SirRaffleBuffle suggested, just do set.length. Total credits to him
Assuming your example is missing "BB" and "CC" because it includes "AA", it looks like what you want is just like the odometer of a car except that instead of ten digits, you want a choice of letters. It's not hard to model an odometer:
class Odo {
private final char [] chars;
private final int [] positions;
private boolean hasNext;
Oddo(String chars, int nPositions) {
this.chars = chars.toCharArray();
this.positions = new int [nPositions];
this.hasNext = true;
}
boolean hasNext() {
return hasNext;
}
String emitNext() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < positions.length; ++i) sb.append(chars[positions[i]]);
for (int i = 0; i < positions.length; ++i) {
if (++positions[i] < chars.length) {
hasNext = true;
return sb.toString();
}
positions[i] = 0;
}
hasNext = false;
return sb.toString();
}
}
Calling like so:
Odo odo = new Odo("AB", 3);
while (odo.hasNext()) {
System.out.println(odo.emitNext());
}
Produces
AAA
BAA
ABA
BBA
AAB
BAB
ABB
BBB
I am trying to solve a problem "Given an even number ( greater than 2 ), return two prime numbers whose sum will be equal to given number." and getting the above error.
Error is due to code complexity which is clear.
Please suggest any way to reduce complexity
My code is:
public ArrayList<Integer> primesum(int A) {
ArrayList<Integer> arr = new ArrayList<Integer>();
for(int i=0;i<=A;i++)
{
//All the numbers are prime
arr.add(1);
}
arr.set(0,0);//
arr.set(1,0);
for(int i=2; i<=Math.sqrt(A);i++)
{
if(arr.get(i)==1)
for(int j=2;i*j<=A;j++)
{
arr.set(i*j,0);
}
}
for(int i=0;i<=Math.sqrt(A);i++)
{
if(arr.get(i)==1)
{
boolean b = checkprime((A-i));
if(b)
{
arr.clear();
arr.add(i);
arr.add(A-i);
break;
}
}
}
return arr;
}
private static boolean checkprime(int p)
{
boolean k =true;
if(p==1)
return false;
for(int i=2;i<=Math.sqrt(p);i++)
{
if(p%i==0)
k=false;
}
return k;
}
The first step in your algorithm constructs a list of all Integers up to A, which could potentially be very large. The wrapper classes are quite inefficient, each Integer takes 16 bytes, not to mention the space the List takes. Since you know the size of this list, I'd suggest using an int array instead, with code something like:
public int[] primesum(int A) {
int[] arr = new int[A + 1];
for (int i = 0; i <= A; i++) {
// All the numbers are prime
arr[i] = 1;
}
arr[0] = 0;//
arr[1] = 0;
for (int i = 2; i <= Math.sqrt(A); i++) {
if (arr[i] == 1)
for (int j = 2; i * j <= A; j++) {
arr[i * j] = 0;
}
}
for (int i = 0; i <= Math.sqrt(A); i++) {
if (arr[i] == 1) {
boolean b = checkprime((A - i));
if (b) {
arr = new int[2];
arr[0] = i;
arr[1] = A - i;
break;
}
}
}
return arr;
}
private static boolean checkprime(int p) {
boolean k = true;
if (p == 1)
return false;
for (int i = 2; i <= Math.sqrt(p); i++) {
if (p % i == 0)
k = false;
}
return k;
}
(It's still possible to get heap errors with very large values of A, but with this version they at least happen as soon as the array is declared. To optimize further I'm afraid you'd need to rethink your algorithm to not need that array, although of course as olambert says, you could always resize your heap space to make it fit.)
You can increase the heap size of your java application which will allow you to process a larger set of data before running out of memory. You can specify the heap size for your application by using -Xms and -Xmx flags when you run your program. For example:
java -Xmx1G myProgram
would run "myProgram" with a maximum heap size of 1GB. You can get more information about jvm arguments you can specify by running:
java -X
Of course you may find that you need to use a more efficient algorithm which uses less memory if you need to solve the problem for large integers.
The following algorithm uses Sieve of Eratosthenes for generating all prime numbers lesser than the given number and then checks if their sum equals the given number and returns valid pairs. This approach spares the use of checkPrime() method altogether:
public static void main(String[] args) {
// TODO Auto-generated method stub
int n = 120;
int[] chk = new int[n];
chk[0]=1;
chk[1]=1;
for(int i=2;i<n;i++) {
if(chk[i]!=1){
chk[i]=-1;
}
if(chk[i]==1) {
continue;
} else {
for(int j=2;j*i<n;j++){
chk[j*i]=1;
}
}
}
for(int i=2;i<n/2;i++) {
if(chk[i]==-1) {
if(chk[n-i]==-1) {
System.out.println(i+"+"+(n-i));
}
}
}
}
o/p
7+113
11+109
13+107
17+103
19+101
23+97
31+89
37+83
41+79
47+73
53+67
59+61
Hope that helps. You can throw in a break to skip loop after one matching pair is found.(I haven't quite checked the corner cases so there might be some issues with the code but hope it gets the idea across)
This is a follow-up to my previous question that I asked yesterday. I wrote a Bubble Sort method that analyzes an array of strings and returns the NUMBER of comparisons that the method has made when ordering the array into alphabetical order (the assignment is to write several types of sorting methods and graph the number of comparisons each one makes, to see which is most efficient).
This is my code:
public static void main(String[] args)
{
String[] test_array = {"bill", "phil", "adam"};
/*
System.out.println(compare("orange", "boogie"));
*/
System.out.println(bubbleSort(test_array));
}
public static int compare(String a, String b)
{
int len = Math.min (a.length(),b.length());
// looping through every character. If cha is less than chb, the method returns -1, and so on.
for (int i = 0; i<len; i++) {
char cha = a.charAt(i);
char chb = b.charAt(i);
if (cha < chb) {
return -1;
} else if (cha > chb) {
return 1;
}
}
// Now we account for the length of the word, since it could be the same word.
if (a.length() < b.length())
return -1;
else if (a.length() > b.length())
return 1;
// Seems to be the same String, so return 0.
else
return 0;
}
public static int bubbleSort(String[] test_array) {
boolean swapped = true;
// Variable to track number of comparisons.
int compNumber = 0;
while (swapped == true) {
swapped = false;
for (int i = 1; i < test_array.length; i++) {
// Tracking the number of comparisons
compNumber++;
if (compare(test_array[i-1], test_array[i]) > 0) {
//Switching the variables by use of a temp variable
String temp = test_array[i-1];
test_array[i-1] = test_array[i];
test_array[i] = temp;
swapped = true;
}
else {
swapped = true;
}
}
}
return compNumber;
}
So the compare method compares two strings (given by the array) and determines if they are in alphabetical order (returns -1) or not (returns 1), or is the same word (returns 0). Then, the bubble sort method calls upon the compare method to go through the array, and it then makes the switches, while my compNumber variable counts the number of times the loop (therefore the number of comparisons) runs.
It compiles fine, but it unfortunately doesn't stop running and doesn't return anything. I've waited 5 minutes so I've determined that something is wrong, probably with my loops. I can't seem to find an issue, having manipulated the parameters of the loops several times. Could anyone help me out? Thanks in advance.
"swapped" will always be true, hence the while will never end looping.
I think you meant to put swapped = false in the else statement
you need to set one of these two swapped = false... or else you will never exit the while loop because swapped = true always ... probably changing the second one makes sense !
if (compare(test_array[i-1], test_array[i]) > 0) {
//Switching the variables by use of a temp variable
String temp = test_array[i-1];
test_array[i-1] = test_array[i];
test_array[i] = temp;
swapped = true;
}
else {
swapped = true;
}
I'm looking to make this much quicker. I've contemplated using a tree, but I'm not sure if that would actually help much.
I feel like the problem is for most cases you don't need to calculate all the possible maximums only a hand full, but I'm not sure where to draw the line
Thanks so much for the input,
Jasper
public class SpecialMax {
//initialized to the lowest possible value of j;
public static int jdex = 0;
//initialized to the highest possible value of i;
public static int idex;
//will hold possible maximums
public static Stack<Integer> possibleMaxs = new Stack<Integer> ();
public static int calculate (int[] a){
if (isPositive(a)){
int size = a.length;
int counterJ;
counterJ = size-1;
//find and return an ordered version of a
int [] ordered = orderBySize (a);
while (counterJ>0){
/* The first time this function is called, the Jvalue will be
* the largest it can be, similarly, the Ivalue that is found
* is the smallest
*/
int jVal = ordered[counterJ];
int iVal = test (a, jVal);
possibleMaxs.push(jVal-iVal);
counterJ--;
}
int answer = possibleMaxs.pop();
while (!possibleMaxs.empty()){
if (answer<possibleMaxs.peek()){
answer = possibleMaxs.pop();
} else {
possibleMaxs.pop();
}
}
System.out.println("The maximum of a[j]-a[i] with j>=i is: ");
return answer;
} else {
System.out.println ("Invalid input, array must be positive");
return 0; //error
}
}
//Check to make sure the array contains positive numbers
public static boolean isPositive(int[] a){
boolean positive = true;
int size = a.length;
for (int i=0; i<size; i++){
if (a[i]<0){
positive = false;
break;
}
}
return positive;
}
public static int[] orderBySize (int[] a){
//orders the array into ascending order
int [] answer = a.clone();
Arrays.sort(answer);
return answer;
}
/*Test returns an Ival to match the input Jval it accounts for
* the fact that jdex<idex.
*/
public static int test (int[] a, int jVal){
int size = a.length;
//initialized to highest possible value
int tempMin = jVal;
//keeps a running tally
Stack<Integer> mIndices = new Stack<Integer> ();
//finds the index of the jVal being tested
for (int i=0; i<size; i++) {
if (jVal==a[i]){
//finds the highest index for instance
if (jdex<i){
jdex = i;
}
}
}
//look for the optimal minimal below jdex;
for (int i=0; i<jdex; i++){
if (a[i]<tempMin){
tempMin = a[i];
mIndices.push(i);
}
}
//returns the index of the last min
if (!mIndices.empty()){
idex = mIndices.pop();
}
return tempMin;
}
}
It can be done in linear time and linear memory. The idea is: find the minimum over each suffix of the array and maximum over each prefix, then find the point where the difference between the two is the highest. You'll also have to store the index on which the maximum/minimum for each prefix is reached if you need the indices, rather than just the difference value.
Pre-sorting a[] makes the procedure complicated and impairs performance. It is not necessary, so we leave a[] unsorted.
Then (EDITED, because I had read j>=i in the body of your code, rather than i>=j in the problem description/title, which I now assume is what is required (I didn't go over your coding details); The two varieties can easily be derived from each other anyway.)
// initialize result(indices)
int iFound = 0;
int jFound = 0;
// initialize a candidate that MAY replace jFound
int jAlternative = -1; // -1 signals: no candidate currently available
// process the (remaining) elements of the array - skip #0: we've already handled that one at the initialization
for (int i=1; i<size; i++)
{
// if we have an alternative, see if that combines with the current element to a higher "max".
if ((jAlternative != -1) && (a[jAlternative]-a[i] > a[jFound]-a[iFound]))
{
jFound = jAlternative;
iFound = i;
jAlternative = -1;
}
else if (a[i] < a[iFound]) // then we can set a[iFound] lower, thereby increasing "max"
{
iFound = i;
}
else if (a[i] > a[jFound])
{ // we cannot directly replace jFound, because of the condition iFound>=jFound,
// but when we later may find a lower a[i], then it can jump in:
// set it as a waiting candidate (replacing an existing one if the new one is more promising).
if ((jAlternative = -1) || (a[i] > a[jAlternative]))
{
jAlternative = i;
}
}
}
double result = a[jFound] - a[iFound];