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;
}
}
Related
I am trying to solve a question in which I am given a String array of words and I have to check whether they have all same length or not. For instance if am given the array {"apple","purple","lemon"} then my method should return true, and when I am given the array {"red","blue"}, it should return false.
This is what I did so far but it is not working. I appreciate any help.
public static boolean allEqualLength(String[] myArray){
int i;
for(i=0;i<myArray.length;i++){
if(myArray[i]!=myArray[i+1])
return false;
}
return true,
}
All items having the same length is equivalent to saying all items must have the same length as the first item:
public static boolean allEqualLength(String[] myArray) {
// zero items => "all" items have same length:
if (myArray.length == 0) return true;
final int expectedLength = myArray[0].length();
for(int i = 0; i < myArray.length; ++i) {
if(myArray[i].length() != expectedLength)
return false;
}
return true,
}
But your original solution was not that far off. You just need to make sure not to exceed the array's bounds and to compare the string lengths, not the strings themselves:
public static boolean allEqualLength(String[] myArray) {
for(int i=0; i < myArray.length - 1; i++) { // -1 to not exceed bounds
if(myArray[i].length() != myArray[i+1].length()) // compare length, not memory addresses
return false;
}
return true,
}
I world do something like that:
public static boolean allEqualLength(String[] myArray) {
int strLength = myArray[0].length();
for (String str :
myArray) {
if (str.length() != strLength)
return false;
}
return true;
}
Like that you can avoid any indexing problems in your loop.
You are trying to compare the strings themselves. You should compare the length only.
myArray[i].length() != myArray[i + 1].length()
By the way, this will throw an ArrayIndexOutOfBoundsException, because you are trying to access index myArray[myArray.length]. Change the for loop to
for (int i = 0; i < myArray.length - 1; i++) {
if (myArray[i].length() != myArray[i + 1].length()) {
return false;
}
}
Also make sure you return true if the array length is 0 or 1, because the loop can't handle those.
For example you have array with length 4 , you have the positions 0,1,2,3 so in your code you run with : myArray[i]!=myArray[i+1] so on the last run you check the positions :
3 and 4 and you will get ArrayIndexOutOfBoundsException , you need to change to : length-1 on the loop condition like this :
public static boolean allEqualLength(String[] myArray){
int i;
for(i=0;i<myArray.length -1;i++){
if(myArray[i].length() != myArray[i+1].length())
return false;
}
return true,
}
If you run on myArray.length ,the positions that check :
0--1
1--2
2--3
3--4 // ERROR !!! ArrayIndexOutOfBoundsException !!
If you run on myArray.length-1 ,the positions that check :
0--1
1--2
2--3 -OK !!!
So on this way if you run the array with : myArray.length-1 , you will not get ArrayIndexOutOfBoundsException .
First things first you are not checking element lengths other issue is your for loop would try to access array index out of bounds since you have i+1, last element is already being checked that way, considering that you just need for until myArray.length - 1.
Using your code it would look something like this:
public static boolean allEqualLength(String[] myArray) {
for (int i = 0; i < myArray.length - 1; i++) {
if (myArray[i].length() != myArray[i + 1].length())
return false;
}
return true;
}
If performance is not an issue and you will not use it in 1 million strings or something, in addition to all these answers, here is an one liner:
boolean allStringsEqualLength = Stream.of(array)
.map(String::length).distinct().count() == 1;
The idea is to map each string to its length. So if distinct() stream contains only one value, that means all strings had the same length.
I'm having a little trouble wrapping my head around this logic and thought I had a fix but am stumped now.
The goal is to create a 4 digit pin and have 3 unique numbers and 1 can be a duplicate. They can be in any order as well. Here is what i have so far:
boolean UniqueNums(String nums)
{
for (int i=0; i < 3; i++)
for (int j=i+1; j < 3; j++)
if (nums.charAt(i) == nums.charAt(j))
return false;
// If no duplicate characters encountered,
// return true
return true;
}
So if i pass the numbers 1137 it fails but other like 1371 pass.
I feel this is the different then the linked duplicate answer link, due to im not trying to do it in one line and I'm not just counting the number of times the number occurs. More a long the lines of validating the values being passed.
Any help or advice would be appreciated.
What about:
boolean UniqueNums(String data) {
Set<Character> found = new HashSet<>();
int count = 0;
for (char c : data.toCharArray()) {
boolean noClash = found.add(c);
count += (noClash ? 0 : 1);
if (count == 2) {
return false;
}
}
return true;
}
1234 returns true (no duplicate)
1231 returns true (a single duplicate)
1221 returns false (a pair of duplicates)
1112 returns false (a number used more than twice)
It also works if your PIN is longer then 4 characters, it only requires a single loop making it O(n), and it fails fast
Instead of nested for loops (with complexity O(n^2)), you can use hashing to count the occurrences of each digit and then check for valid pin number. Here is algorithm:
static boolean UniqueNums(String digit){
int array[] = new int[10];
for (int i=0;i<digit.length();i++){
array[digit.charAt(i)-48]++; //48 because ascii of 0 is 48
}
//Now check for frequency
int count = 0;
for (int i=0;i<10;i++){
if(array[i] > 2) return false;
if(array[i] == 2){
++count;
}
}
if(count <= 1) return true;
return false;
}
This will be of O(k), where k is number of digits in your number.
Because of the numeric limitations involved, your predicate can be reduced from:
a 4 digit pin and have 3 unique numbers and 1 can be a duplicate. they can be in any order as well.
to
have 3 unique characters
(Your code doesn't test for digits and length so I assume some other code does that.)
boolean hasAtLeastThreeUniqueCharacters = "1123".codePoints().distinct().count() >= 3;
You only need one additional int to maintain bit mask for each of the digits. A short would do but it gets widened to int in Integer.bitCount() call either way.
boolean uniqueNums(String nums) {
int pin = Integer.parseInt(nums);
int mask = 0;
for (int i = 0; i < nums.length(); i++) {
mask |= 1 << pin % 10;
pin /= 10;
}
return Integer.bitCount(mask) >= 3;
}
resulting in
uniqueNums("1234") // true
uniqueNums("9393") // false
You could also group numbers by occurrences, filter those which are at most 2 occurrences and so that their count could be as long as num length, or length - 1 (one duplicate) :
boolean atMostOneOneDuplicate(String num) {
long occurences = num.chars()
.mapToObj(i -> (char) i)
.collect(Collectors.groupingBy(c -> c, Collectors.counting()))
.entrySet()
.stream()
.map(Map.Entry::getValue)
.filter(v -> v < 3)
.count();
return occurences == num.length() || occurences == num.length() - 1;
}
I think keeping counters in a Map is simpler:
public boolean UniqueNums(String pin){
if(pin.length() > 4) {
//pin too long
return false;
}
Map<Character, Integer> counters = new HashMap<>();
for(int i = 0; i < pin.length(); i++){
Character c = pin.charAt(i);
if(!Character.isDigit(c)){
//not a number.
return false;
}
counters.put(c, counters.getOrDefault(c,0) + 1);
if(counters.get(i) > 2){
// digit appear 3 times.
return false;
}
}
if(counters.keySet().size() < pin.length() - 1){
// not 3 unique numbers e.g 1122
return false;
}
return true;
}
Use a map to keep track of occurances
import java.util.HashMap;
import java.util.Map;
class Main{
public static void main(String[] args) {
System.out.println(isValid("1137"));
System.out.println(isValid("1371"));
System.out.println(isValid("1234"));
System.out.println(isValid("1222"));
}
public static boolean isValid(String num){
Map<Character,Integer> digitsWithNumberOfOccurances = new HashMap<>();
int numOfDigitsThatOccuredTwice = 0;
for(int i = 0; i < num.length(); i++){
char currentChar = num.charAt(i);
int currentNumberOfOccurences = digitsWithNumberOfOccurances.getOrDefault(currentChar,0);
currentNumberOfOccurences ++;
digitsWithNumberOfOccurances.put(currentChar,currentNumberOfOccurences);
if(currentNumberOfOccurences == 2){
numOfDigitsThatOccuredTwice++;
// only one digit can occur twice
if(numOfDigitsThatOccuredTwice > 1) {
return false;
}
}else if(currentNumberOfOccurences > 2){ // no digit can occur more than twice
return false;
}
}
return true;
}
}
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.
I am trying to program a Ruzzle solver Java application for learning purpose.
I have a little problem in th ematter of "finding words" in a Ruzzle-type map.
Example of a Ruzzle map (it is composed of 4 rows and 4 columns of 1 letter in each cell) :
Z O O H
E Y L H
I E L I
H O F M
http://www.maclife.com/files/imagecache/futureus_imagegallery_fullsize/gallery/ruzzle1.jpg
I would like to obtain a list of all possible words you can find in such a map.
The difficulty : you can find a word by appending letters vertically, horizontally and diagonally (example : "HELLO").
So far, I created 3 classes :
Ruzzlesolver.java
Letter.java
Map.java
The Letter class
Describes a single Letter of the map, its fields are the X and Y positions and the character of the cell.
The Ruzzlesolver class
This is the main class.
it reads the Ruzzle map (an line by line input in the console)
it reads the dictionnary.txt file
it compares the map with the dictionnary file
it writes into the results.txt file
Each line is stored in a char array.
Then I create a new Map object from the 4 obtained arrays.
The Map class
This is the constructor of the Map objects :
public Map(final char[] pTab1, final char[] pTab2, final char[] pTab3, final char[] pTab4)
{
this.aLettres = new ArrayList<Letter>();
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(1, i+1, pTab1[i]));}
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(2, i+1, pTab2[i]));}
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(3, i+1, pTab3[i]));}
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(4, i+1, pTab4[i]));}
}
this.aLettres is the ArrayList that contains each of the 16 letters of the map.
Each Letter knows its column (X position : "i+1"), its row (Y position : "1, 2, 3 and 4") and its character ("pTab[i]").
Now that we know the map and the place of each letter, we can begin to find the words.
The contains() method
This is my problem : I am stuck using the following method :
How it is called
I pick a word from the dictionnary in the Ruzzlesolver class.
I call the contains() method on my Map object, with this word as a parameter :
if (this.aMap.contains(vMot)) {/*print vMot in the result.txt file*/}
How does the contains() method work
Variables :
char[] vChars = new char[pMot.length()];
ArrayList<Letter> vFoundCharS1 = new ArrayList<Letter>();
Stocking each characters of pMot in an ArrayList :
for (int i = 0 ; i < pMot.length() ; i++) {
vChars[i] = pMot.charAt(i);
}
Searching for the first character of pMot :
for (Letter vL : this.aLettres) {
if (vL.getChar() == vChars[0]) {
vFoundCharS1.add(vL);
return true;
}
}
I am stuck.
If I continue this method, I will have to create longer and longer blocks as I progress. Besides, I would need to write 16 blocks to consider every length possibility.
I am sure this is a wrong method. How would you implement such a treatment ?
Thanks a lot in advance for your help.
PS : I apologize for grammar/English mistakes, English is not my natal language.
If I understand the problem correctly, you can pick every adjacent cell for the next letter, right? In that case, the code below would (I think) solve your problem.
I changed the constructor of Map, because it is easier to work with a two-dimensional array of char.
The function contains does just what your step 3 described: find the first letter and try searching on from there. The function findRecursively searches for the rest of the word recursively.
public class Map {
private char[][] board;
public Map(final char[] pTab1, final char[] pTab2,
final char[] pTab3, final char[] pTab4) {
board = new char[4][4];
for (int i = 0 ; i < 4 ; i++) {
board[0][i] = pTab1(i);
board[1][i] = pTab2(i);
board[2][i] = pTab3(i);
board[3][i] = pTab4(i);
}
}
public boolean contains(String word) {
char[] array = word.toCharArray();
// empty string is trivial
if (array.length == 0)
return true;
for(int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (board[i][j] == array[0] && findRecursively(i, j, array, 1))
return true;
}
}
return false;
}
public boolean isValid(int i, int j) {
return (0 <= i && i < 4) && (0 <= j && j < 4);
}
public boolean findRecursively(int i, int j, char[] array, int index) {
// reached end of word
if (index == array.length) {
return true;
} else {
// loop over all neighbors
for (int di = -1; di <= 1; di++) {
for (int dj = -1; dj <= 1; dj++) {
// skip cell itself and invalid cells
if (!(di == 0 && dj == 0) && isValid(i+di, j+dj)) {
if (board[i+di][j+dj] == array[index]
&& findRecursively(i+di, j+dj, array, index+1))
return true;
}
}
}
return false;
}
}
}
So im working on java codingbat and this is the question:
Given a string, look for a mirror image (backwards) string at both the beginning and end of the given string.
In other words, zero or more characters at the very begining of the given string, and at the very end of the string in reverse order (possibly overlapping).
For example:
the string "abXYZba" has the mirror end "ab". mirrorEnds("abXYZba") → "ab" mirrorEnds("abca") → "a" mirrorEnds("aba") → "aba" .
My code passed all the test except for the other test, which is not specified. I dont know what's wrong with it.
public String mirrorEnds(String string) {
String input = string, mirror = "";
int length = string.length();
for (int n = 0; n < (length+1) / 2; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}else if(length%2 == 1 && n == (length - 1)/2){
// System.out.println("length/2 = " );
return input;
}
else {
mirror += input.charAt(n);
}
}
return mirror;
}
You were correct in not needing to go though the entire word, but your logic is more complex than it needs to be, making it harder to find and fix the problem. The root cause of the test failure is in the last return statement. It must return string if the loop completes without breaking. You can fix your code by changing break; to return mirror; and changing the last return mirror; to return input;
The test that is failing is one like this:
mirrorEnds("abba") -> "abba"
A much simpler version of your code can be created like this:
public String mirrorEnds(String string) {
int len = string.length();
for (int i=0; i < len/2; ++i)
if (string.charAt(i) != string.charAt(len - 1 - i))
return string.substring(0, i);
return string;
}
mirrorEnds("abba")?
Anyways, I'm sure you could come up with a better question name than "some weird stuff"...
Since you are dividing n by 2 in your loop termination condition, it will end when halfway through the word. This is enough to tell the word is a palindrome, but not enough to build your output correctly. You have a condition handling palindrome with odd numbers of letter, but not even numbers of letters. I believe the failing test will be of the form "abba", where I believe what you have will return "ab", instead of "abba".
If you change you loop to:
for (int n = 0; n < length; n++) {
I believe it should be doing what you want. This also makes the short circuit case unnecessary, so:
for (int n = 0; n < length; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}
else {
mirror += input.charAt(n);
}
}
The first test I tried was with the string "abba" which fails. It returns ab, and not abba. As femtoRgon mentioned, you're not going through the entire word, which may some times be necessary. femtoRgon's solution works, as well as taking a slightly different approach to iterating through the word as follows:
public String mirrorEnds(String string) {
boolean matches = true;
StringBuilder mirrorEnd = new StringBuilder();
int index = 0;
while (matches && index < string.length()) {
if (string.charAt(index) == string.charAt(string.length() - index - 1))
mirrorEnd.append(string.charAt(index));
else
matches = false;
index++;
}
return mirrorEnd.toString();
}
public String mirrorEnds(String string) {
String comp="";
for(int i=0; i<string.length(); i++){
if(string.charAt(i)==string.charAt(string.length()-(i+1)))
comp= comp+ string.charAt(i);
else break;
}
return comp;
}