I am struggling to understand how the leetcode solution for the above problem works. If any help on how the post increment operator is working on the value of the array it would be great.
class Solution {
public int firstUniqChar(String s) {
int [] charArr = new int[26];
for(int i=0;i<s.length();i++){
charArr[s.charAt(i)-'a']++;
}
for(int i=0;i<s.length();i++){
if(charArr[s.charAt(i)-'a']==1) return i;
}
return -1;
}
The problem link here https://leetcode.com/problems/first-unique-character-in-a-string/submissions/!
First, you need to understand there are 26 letters in the English alphabet. So the code creates an array of 26 integers that will hold the count of each letter in the string.
int [] charArr = new int[26];
The count of all a's will be at index 0, the cound of all b's at index 1, etc. The default value for int is 0, so this gives an array of 26 zeros to start with.
Each letter has two character codes; one for upper case and one for lower case. The function String.charAt() returns a char but char is an integral type so you can do math on it. When doing math on a char, it uses the char code. So for example:
char c = 'B';
c -= 'A';
System.out.println((int)c); // Will print 1 since char code of 'A' = 65, 'B' = 66
So this line:
charArr[s.charAt(i)-'a']++;
Takes the char at i and subtracts 'a' from it. The range of lower case codes are 97-122. Subtracting 'a' shifts those values to 0-25 - which gives the indexes into the array. (Note this code only checks lower case letters).
After converting the character to an index, it increments the value at that index. So each item in the array represents the character count of the corresponding letter.
For example, the string "aabbee" will give the array {2, 2, 0, 0, 2, 0, 0....0}
I am looking to amend the values of a string IF certain positions within a string are certain values for example I have a postcode L65 OBH and I need to do the following:
(1)
If the 1st value in the first section of the string (split by white space) = L it needs to be changed to T. This would then give:
T65 OBH
(2)
Then if the 2nd value in the first section of the string (split by white space) = 6 it needs to be changed to 7. This would then give:
T75 OBH
(3)
Then if the 1st value in the second section of the string (split by white space) = O it needs to be changed to 2. This would then give:
T75 2BH
(4)
Then if the 3rd value in the second section of the string (split by white space) = H it needs to be changed to P. This would then give:
T75 2BP
I'm assuming that I need to use replaceall and a number of IF statements but I am struggling to work this out, particularly how to split the 2 different parts of the postcode out treat them as separate enteties....can anyone help please
I'd write a helper method for the replacement rules:
def postcode = 'L65 0BH'
def (first, second) = postcode.split(/\s+/)
def replaceIf(String token, int position, String match, String replacement) {
(0..<token.length()).collect { index ->
if(index == position && token[index] == match) {
replacement
}
else {
token[index]
}
}.join()
}
first = replaceIf(first, 0, 'L', 'T')
first = replaceIf(first, 1, '6', '7')
second = replaceIf(second, 0, '0', '2')
second = replaceIf(second, 2, 'H', 'P')
assert "$first $second" == 'T75 2BP'
def strVal= "L65 OBH"
strVal.replaceFirst(/^L/, "T")
def strVal1= "L65 OBH"
strVal1.replaceFirst(/^6/, "7")
and so on using the same replaceFirst() method
I have set of strings
[abcd,
efgh,
abefg]
How to find the minimum number of strings that covers all the characters (abcdefgh)
Answer would be abcd and efgh. But what would be the algorithm to find this answer?
The "set cover problem" can be reduced to your problem. You can read about it on Wikipedia link. There is no known polynomial solution for it.
#j_random_hacker: That's what I meant. Corrected.
#Yuvaraj: Check the following pseudo code:
str = input string
S = input set
for each subset s of S in ascending order of cardinality:
if s covers str
return s
return none
python
>>> a="abcd efgh abefg"
>>> set(a)
set(['a', ' ', 'c', 'b', 'e', 'd', 'g', 'f', 'h'])
>>> ''.join(set(a))
'a cbedgfh'
>>> ''.join(set(a)-set(' '))
'acbedgfh'
If you want to check every possible combination of strings to find the shortest combination which covers a set of characters, there are two basic approaches:
Generating every combination of strings, and for each one, checking whether it covers the whole character set.
For each character in the set, making a list of strings it appears in, and then combining those lists to find combinations of strings which cover the character set.
(If the number of characters or strings is too big to check all combinations in reasonable time, you'll have to use an approximation algorithm, which will find a good-enough solution, but can't guarantee to find the optimal solution.)
The first approach generates N! combinations of strings (where N is the number of strings) so e.g. for 13 strings that is more than 2^32 combinations, and for 21 strings more than 2^64. For large numbers of strings, this may become too inefficient. On the other hand, the size of the character set doesn't have much impact on the efficiency of this approach.
The second approach generates N lists of indexes pointing to string (where N is the number of characters in the set), and each of these lists holds at most M indexes (where M is the number of strings). So there are potentially M^N combinations. However, the number of combinations that are actually considered is much lower; consider this example with 8 characters and 8 strings:
character set: abcdefg
strings: 0:pack, 1:my, 2:bag, 3:with, 4:five, 5:dozen, 6:beige, 7:eggs
string matches for each character:
a: [0,2]
b: [2,6]
c: [0]
d: [5]
e: [4,5,6,7]
f: [4]
g: [2,6,7]
optimal combinations (size 4):
[0,2,4,5] = ["pack,"bag","five","dozen"]
[0,4,5,6] = ["pack,"five","dozen","beige"]
Potentially there are 2x2x1x1x4x1x3 = 48 combinations. However, if string 0 is selected for character "a", that also covers character "c"; if string 2 is selected for character "a", that also covers characters "b" and "g". In fact, only three combinations are ever considered: [0,2,5,4], [0,6,5,4] and [2,0,5,4].
If the number of strings is much greater than the number of characters, approach 2 is the better choice.
code example 1
This is a simple algorithm which uses recursion to try all possible combinations of strings to find the combinations which contain all characters.
Run the code snippet to see the algorithm find solutions for 12 strings and the whole alphabet (see console for output).
// FIND COMBINATIONS OF STRINGS WHICH COVER THE CHARACTER SET
function charCover(chars, strings, used) {
used = used || [];
// ITERATE THROUGH THE LIST OF STRINGS
for (var i = 0; i < strings.length; i++) {
// MAKE A COPY OF THE CHARS AND DELETE THOSE WHICH OCCUR IN THE CURRENT STRING
var c = chars.replace(new RegExp("[" + strings[i] + "]","g"), "");
// MAKE A COPY OF THE STRINGS AFTER THE CURRENT STRING
var s = strings.slice(i + 1);
// ADD THE CURRENT STRING TO THE LIST OF USED STRINGS
var u = used.concat([strings[i]]);
// IF NO CHARACTERS ARE LEFT, PRINT THE LIST OF USED STRINGS
if (c.length == 0) console.log(u.length + " strings:\t" + u)
// IF CHARACTERS AND STRINGS ARE LEFT, RECURSE WITH THE REST
else if (s.length > 0) charCover(c, s, u);
}
}
var strings = ["the","quick","brown","cow","fox","jumps","over","my","lazy","cats","dogs","unicorns"];
var chars = "abcdefghijklmnopqrstuvwxyz";
charCover(chars, strings);
You can prune some unnecessary paths by adding this line after the characters are removed with replace():
// IF NO CHARS WERE DELETED, THIS STRING IS UNNECESSARY
if (c.length == chars.length) continue;
code example 2
This is an algorithm which firsts creates a list of matching strings for every character, and then uses recursion to combine the lists to find combinations of strings that cover the character set.
Run the code snippet to see the algorithm find solutions for 24 strings and 12 characters (see console for output).
// FIND COMBINATIONS OF STRINGS WHICH COVER THE CHARACTER SET
function charCover(chars, strings) {
// CREAT LIST OF STRINGS MATCHING EACH CHARACTER
var matches = [], min = strings.length, output = [];
for (var i = 0; i < chars.length; i++) {
matches[i] = [];
for (var j = 0; j < strings.length; j++) {
if (strings[j].indexOf(chars.charAt(i)) > -1) {
matches[i].push(j);
}
}
}
combine(matches);
return output;
// RECURSIVE FUNCTION TO COMBINE MATCHES
function combine(matches, used) {
var m = []; used = used || [];
// COPY ONLY MATCHES FOR CHARACTERS NOT ALREADY COVERED
for (var i = 0; i < matches.length; i++) {
for (var j = 0, skip = false; j < matches[i].length; j++) {
if (used.indexOf(matches[i][j]) > -1) {
skip = true;
break;
}
}
if (! skip) m.push(matches[i].slice());
}
// IF ALL CHARACTERS ARE COVERED, STORE COMBINATION
if (m.length == 0) {
// IF COMBINATION IS SHORTER THAN MINIMUM, DELETE PREVIOUSLY STORED COMBINATIONS
if (used.length < min) {
min = used.length;
output = [];
}
// CONVERT INDEXES TO STRINGS AND STORE COMBINATION
var u = [];
for (var i = 0; i < used.length; i++) {
u.push(strings[used[i]]);
}
output.push(u);
}
// RECURSE IF CURRENT MINIMUM NUMBER OF STRINGS HAS NOT BEEN REACHED
else if (used.length < min) {
// ITERATE OVER STRINGS MATCHING NEXT CHARACTER AND RECURSE
for (var i = 0; i < m[0].length; i++) {
combine(m, used.concat([m[0][i]]));
}
}
}
}
var strings = ["the","quick","brown","fox","jumps","over","lazy","dogs","pack","my","bag","with","five","dozen","liquor","jugs","jaws","love","sphynx","of","black","quartz","this","should","do"];
var chars = "abcdefghijkl";
var result = charCover(chars, strings);
for (var i in result) console.log(result[i]);
This algorithm can be further optimised to avoid finding duplicate combinations with the same strings in different order. Sorting the matches by size before combining them may also improve efficiency.
Thanks everyone for the response,
Finally completed it, have given the algorithm below in simple words as a refernce for others
Sub optimize_strings()
Capture list of strings in an array variable & number of strings in an integer
Initialize array of optimized strings as empty & pointer to it as zero
Get the list of all characters in an array & number of characters in a variable
Do While number of characters>0
Reset the frequency of all characters as zero & then calculate the frequency of all characters in uncovered strings in separate array
Reset the number of uncovered characters for each strings as zero & then calculate the number of uncovered characters in each strings in separate array
Sort the characters in characters array in ascending order based on their characters frequency array
Fetch list of strings that contains the character present in the top of the character array & place them in filtered strings array
Bubble sort filtered strings array in descending order based on the number of uncovered characters which was stored in step 2 of this loop
Store the Top of the filtered strings array in optimized strings array & increase its pointer to 1
Iterate through all the characters in the optimized string & remove all the characters present in it from characters array
Loop
Print the result of optimized strings present in optimized strings array
End Sub
I have a string : str='HDEABGCF'. How can I create the new pairs which is from the second is combined with the third elements, the fourth with fifth , the sixth is combined with the seventh?
The expected output should be: result={'DE';'AB';'GC'}
You can abuse arrayfun, and ensuring you start from the second index of the string array going up to the second last index in increments of 2. For each index, you'd access the string at the current index and the next index after that point, then ensure that the output is a cell array by using the uni=0 flag:
>> str='HDEABGCF';
>> result = arrayfun(#(x) str([x x+1]), 2:2:numel(str)-1, 'uni', 0);
>> result
result =
'DE' 'AB' 'GC'
I have a cell array of strings. I need to extract say 1-to-n characters for each item. Strings are always longer than n characters. Please see:
data = { 'msft05/01/2010' ;
'ap01/01/2013' }
% For each string, last 10 characters are removed and put it in the next column
answer = { 'msft' '05/01/2010' ;
'ap' '01/01/2013' }
Is there a vectorized solution possible? I have tried using cellfun but wasn't successful. Thanks.
data = { 'msft05/01/2010' ;
'ap01/01/2013' };
for i = 1:length(data)
s = data{i};
data{i} = {s(1:end-10) s(end-9:end)};
end
Sorry, didn't notice that you need vectorized... Perhaps I can suggest only one-liner...
data = cellfun(#(s) {s(1:end-10) s(end-9:end)}, data, 'UniformOutput', false);