Alice has two strings, initial and goal. She can remove some number of characters from initial, which will give her a subsequence of that string. A string with no deletions is still considered a subsequence of itself. Given these two strings, can you find the minimum number of subsequences of initial that, when appended together, will form goal?
Functions
minimumConcat() has two parameters:
initial: the source string that you will get subsequences from
goal: the target string that needs to be formed
Input Format
For some of our templates, we have handled parsing for you. If we do not provide you a parsing function, you will need to parse the input directly. In this problem, our input format is as follows:
The first line is the initial String that we will be generating subsequences from
The second line is the goal String to form
Here is an example of the raw input:
abc
bcbac
Expected Output
Return the number of minimum possible subsequences of initial that can be appended together to form goal.
If there are no possible solutions, return -1.
Example minimumConcat() Input #1
initial: "xyz"
goal: "xzyxz"
Output: 3
function minimumConcat(initial, goal) {
//Put your code here.
return 0;
}
Loop the initial string array to form the goal string array.
function minimumConcat(initial, goal) {
initial = initial.split('');
goal = goal.split('');
let res,count=0;
while(true){
if(goal.length > 0){
res = checkChar(initial,goal);
if(false === res){
return -1;
}
}else{
return count;
}
goal = res;
count++;
}
}
function checkChar(initial,goal){
let started = false;
let foundIndex = 0;
for(let i=0; i<initial.length; i++){
if(initial[i] == goal[foundIndex]){
started = true;
foundIndex++;
}
}
if(started){
return goal.slice(foundIndex);
}else{
return false;
}
}
console.log(minimumConcat('abc','bcbac'));
Here you go!
function minimumConcat(initial, goal) {
let result = 0;
let pattern = '';
let count1 = Array.apply(null, Array(26)).map(Number.prototype.valueOf, 0);
let count2 = Array.apply(null, Array(26)).map(Number.prototype.valueOf, 0);
initial.split('').forEach(c => {
pattern = pattern + c
});
pattern = "^[" + pattern + "]*$";
if (!RegExp(pattern).test(goal)) return -1;
for (let i = 0; i < initial.length; i++) {
count1[initial.charCodeAt(i) - 97]++;
}
for (let i = 0; i < goal.length; i++) {
count2[goal.charCodeAt(i) - 97]++;
}
for (let i = 0; i < 26; i++) {
result += Math.abs(count1[i] - count2[i]);
}
return result;
}
console.log(minimumConcat("abc", "bcbac"));
Since this looks like homework I won't give the solution right away, instead here is a suggestion on how to solve it:
I think the hardest part is finding all the sub-strings if you are using Python that's simplified by itertools as mentioned here.
Edit, I didn't notice the javascript tag, you can get the substring set, without a library, with a couple of for loops.
After having all combinations from initial you can sort them to have the longest first. And then go one by one removing them from goal. Counting every time you remove. If, after iterating over all sub-strings, goal is not an empty string then no subsequence of initial can construct goal.
This answers your question using Java
public static int minimumConcat(String initial, String goal) {
HashSet<Character> set = new HashSet<>();
for(char c : initial.toCharArray()) set.add(c);
for(char c : goal.toCharArray()) {
if(!set.contains(c)) return -1;
}
int j = 0, result = 0;
for(int i = 0; i < goal.length();) {
char c = goal.charAt(i);
while(j < initial.length() && initial.charAt(j) != c) j++;
if(j == initial.length()) {
j = 0;
result++;
} else {
j++;
i++;
}
}
result++;
return result;
}
Here is what I've done with python
def minimumConcat(initial, goal):
#verify that goal has all character of initial
res = 0
for i in goal:
if i in initial:
pass
else:
res=-1;
if res != -1:
while goal!="":
a = removefirstGreatestSubstring(initial,goal)
goal=a["goal"];
if a["has"] ==True :
res=res+1
#find the greatest concat
print(res)
def removefirstGreatestSubstring(initial,goal):
has_subtring = False
start = 0
for car in initial:
if car == goal[start]:
has_subtring= True
start = start+1
finalgoal=goal[start:]
return {"goal": finalgoal, "has":has_subtring}
initial = "abc"
goal = "bcbac"
b = minimumConcat(initial, goal)
I've made it using a different approach with regular expressions.
Here a clean version of the code:
"use strict";
// Solution:
function minimumConcat(initial, goal) {
let result = -1;
let goal_slice = goal;
let exp = "", sub = "";
let initial_concat = "";
let matches = 0, count = 0;
let initial_arr = initial.split('');
for(let i = 0 ; i<initial_arr.length; i++){
for(let j = initial_arr.length ; j>i+1; j--){
sub = initial.slice(i,j);
exp = new RegExp(sub,"ig");
matches = (goal_slice.match(exp) || []).length;
if(matches>=1) {
count +=matches;
initial_concat+=sub.repeat(matches);
goal_slice = goal_slice.slice((goal_slice.lastIndexOf(sub)+sub.length));
}
}
}
result = (initial_concat==goal)? count : result;
return result;
}
// Test cases:
let test_cases = [
{initial:"abc", goal: "abcbc"}, // expected result 2
{initial:"abc", goal: "acdbc"}, // expected result -1
{initial:"bcx", goal: "bcbcbc"}, // expected result 3
{initial:"xyz", goal: "xyyz"}, // expected result 2
]
// Running the tests:
test_cases.forEach(function(item,index){
console.log(minimumConcat(item.initial, item.goal));
});
Also, I've included a debug flag to turn on/off console.log messages in order to anybody could easily understand what is happening on each iteration cycle.
"use strict";
// Shwitch for debugging:
const debug = true;
// Solution:
function minimumConcat(initial, goal) {
let exp = "";
let sub = "";
let match = 0;
let count = 0;
let result = -1;
let goal_slice = goal;
let initial_concat = "";
let initial_arr = initial.split('');
for(let i = 0 ; i<initial_arr.length; i++){
for(let j = initial_arr.length ; j>i+1; j--){
sub = initial.slice(i,j);
exp = new RegExp(sub,"ig");
match = (goal_slice.match(exp) || []).length;
if(match>=1) {
count +=match;
initial_concat+=sub.repeat(match);
goal_slice = goal_slice.slice((goal_slice.lastIndexOf(sub)+sub.length));
}
if(debug){
console.log("-----------------------------");
console.log(" i:", i, " - j:", j);
console.log(" exp:", exp);
console.log(" goal:", goal);
console.log(" goal_slice:", goal_slice);
console.log(" match:",match);
}
}
}
result = (initial_concat==goal)? count : result;
if(debug){
console.log("---RESULTS:--------------------------");
console.log("count:",count);
console.log("goal vs initial_concat: ", goal, " - ", initial_concat);
console.log("result: ", result);
}
return result;
}
// Test cases:
let test_cases = [
{initial:"abc", goal: "abcbc"}, // expected result 2
{initial:"abc", goal: "acdbc"}, // expected result -1
{initial:"bcx", goal: "bcbcbc"}, // expected result 3
{initial:"xyz", goal: "xyyz"}, // expected result 2
]
// Running the tests:
test_cases.forEach(function(item,index){
if(debug){
console.log("-----------------------------");
console.log("TEST CASE #",index,":");
console.table(item);
}
minimumConcat(item.initial, item.goal);
});
here is in php
public function index()
{
$init="abc";
$goal="abacabacabacacb";
$res=$this->minimum($init,$goal);
}
public function check($inital,$goal){
$inital=str_split( $inital);
$goal=str_split( $goal);
for($i=0;$i<sizeof($goal);$i++){
if(!in_array($goal[$i],$inital)){
return -1;
}
}
return 0;
}
public function minimum($inital,$goal){
$res=$this->check($inital,$goal);
if($res==-1){
return -1;
}
$counter=0;
$c=0;
$inital=str_split( $inital);
$goal=str_split( $goal);
for($i=0;$i<sizeof($goal);$i++){
for($j=0;$j<sizeof($inital);$j++){
if(($i+$c)<sizeof($goal)){
echo " ".$i." > ".$j." > ".$c." /// ";
if($goal[$i+$c]==$inital[$j]){
$c+=1;
}
}
}
$counter+=1;
if(($i+$c)>=sizeof($goal)){
break;
}
$c=$c-1;
}
return $counter;
}
Here is my python solution
def check_char(initial, goal):
N = len(initial)
started = False
found_index = 0
for i in range(N):
if (initial[i] == goal[found_index]):
started = True
found_index += 1
if(started):
return goal[found_index:]
else:
return '-'
def minimumConcat(initial, goal):
res = 0
count = 0
while(True):
if( len(goal) > 0 ):
res = check_char(initial, goal)
if(res == '-'):
print(-1)
break;
else:
print(count)
break;
goal = res
count += 1
initial = input()
goal = input()
minimumConcat(initial, goal)
Related
I am trying to reverse a string. I am aware of .reverse function and other methods in Js to do so, but i wanted to do it this two-pointer method.
The problem is the string is not getting updated. Is there anything i am not aware of strings. Whats wrong here ?
function reverseString(s) {
let lengthOfStr = 0;
if ((s.length - 1) % 2 == 0) {
lengthOfStr = (s.length - 1) / 2
} else {
lengthOfStr = ((s.length - 1) / 2) + 1;
}
let strLengthLast = s.length - 1;
for (let i = 0; i <= lengthOfStr; i++) {
let pt1 = s[i];
let pt2 = s[strLengthLast];
s[i] = pt2;
s[strLengthLast] = pt1;
console.log('----', s[i], s[strLengthLast]);
strLengthLast--;
}
return s;
}
console.log(reverseString('hello'));
Unlike in C, strings in JavaScript are immutable, so you can't update them by indexing into them. Example:
let s = 'abc';
s[1] = 'd';
console.log(s); // prints abc, not adc
You'd need to do something more long-winded in place of s[i] = pt2;, like s = s.substring(0, i) + pt2 + s.substring(i + 1);, and similarly for s[strLengthLast] = pt1; (or combine them into one expression with 3 calls to substring).
I'm not sure why it doesnt update the string, but if you handle the replacement as an array/list it works as follows:
function reverseString(s) {
let lengthOfStr = 0;
sSplit = s.split("");
if ((s.length - 1) % 2 === 0) {
lengthOfStr = (s.length - 1) / 2
}
else {
lengthOfStr = ((s.length - 1) / 2) + 1;
}
let strLengthLast = s.length - 1;
for (let i = 0; i <= lengthOfStr; i++) {
let pt1 = sSplit[i];
let pt2 = sSplit[strLengthLast];
sSplit[i] = pt2;
sSplit[strLengthLast] = pt1;
console.log('----', sSplit[i], sSplit[strLengthLast],sSplit);
strLengthLast--;
}
return sSplit.join("");
}
console.log(reverseString('Hello'));
returns: Hello => olleH
As covered in comment, answers and documentation, strings are immutable in JavaScript.
The ability to apparently assign a property value to a primitive string value results from early JavaScript engine design that temporarily created a String object from primitive strings when calling a String.prototype method on the primitive. While assigning a property to the temporary object didn't error, it was useless since the object was discarded between calling the String method and resuming execution of user code.
The good news is that this has been fixed. Putting
"use strict";
at the beginning of a JavaScript file or function body causes the compiler to generate a syntax error that primitive string "properties" are read-only.
There are many ways of writing a function to reverse strings without calling String.prototype.reverse. Here's another example
function strReverse(str) {
"use strict";
let rev = [];
for( let i = str.length; i--;) {
rev.push(str[i]);
}
return rev.join('');
}
console.log( strReverse("Yellow") );
console.log( strReverse("").length);
I tried that way, hopefully might be helpful for someone.
const input = 'hello'; /*input data*/
const inputArray = [...input]; /*convert input data to char array*/
function reverseString(inputArray) {
let i = 0;
let j = inputArray.length -1 ;
while(i < j ) {
const temp = inputArray[i];
inputArray[i] = inputArray[j];
inputArray[j] = temp;
i++;
j--;
}
};
reverseString(inputArray);
console.log(inputArray)
const finalResult = inputArray.join("");
console.log(finalResult);
Thanks.
I've been trying to use a for loop to make a code that alternates between two strings and ends with .toUpperCase , but I'm completely stuck. I'm "able" to do it with an array with two strings (and even so it has a mistake, as it ends with the first string of the array...), but not with two separate constants.
Could anyone offer some help?
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
result += i === num - 1 ? frases[0].toUpperCase() : `${frases[0]}, ${frases[1]}, `;
}
return result;
}
console.log(repeteFrases(2));
In order to alternate between two states you can use the parity of the index, i.e., the condition would be i % 2 == 0, like this:
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
result += i % 2 == 0 ? frases[0].toUpperCase() : `${frases[0]}, ${frases[1]}, `;
}
return result;
}
console.log(repeteFrases(5));
You've almost got it.. I think what you're asking for is to repeat phrase one or two (alternating), and for the last version to be uppercase. I notice someone else made your code executable, so I might be misunderstanding. We can test odd/even using the modulus operator (%), which keeps the access of frases to either the 0 or 1 position. The other trick is to loop until one less phrase than needed, and append the last one as upper case.
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
//Only loop to 1 less than the expected number of phrases
const n=num-1;
let result = "";
for (let i = 0; i < n; i++) {
//Note %2 means the result can only be 0 or 1
//Note ', ' is a guess at inter-phrase padding
result+=frases[i%2] + ', ';
}
//Append last as upper case
return result+frases[n%2].toUpperCase();
}
console.log(repeteFrases(2));
console.log(repeteFrases(3));
Use frases[i % frases.length] to alternate the phrases (however many there might be)
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
const next = frases[i % frases.length];
const isLast = (i === num - 1);
result += isLast ? next.toUpperCase() : `${next}, `;
}
return result;
}
console.log(repeteFrases(5));
I'm starting my adventure with javascript and i got one of first tasks.
I must create function that count letter that most occur in string and write this in console.
For example:
var string = "assssssadaaaAAAasadaaab";
and in console.log should be (7,a) <---
the longest string is 7 consecutive identical characters (yes, before count i use .toLowerCase();, because the task requires it)
So far I have it and I don't know what to do next.
Someone want to help?
var string = "assssssadaaaAAAasadaaab";
var string = string.toLowerCase();
function writeInConsole(){
console.log(string);
var count = (string.match(/a/g) || []).length;
console.log(count);
}
writeInConsole();
One option could be matching all consecutive characters using (.)\1* and sort the result by character length.
Then return an array with the length of the string and the character.
Note that this will take the first longest occurrence in case of multiple characters with the same length.
function writeInConsole(s) {
var m = s.match(/(.)\1*/g);
if (m) {
var res = m.reduce(function(a, b) {
return b.length > a.length ? b : a;
})
return [res.length, res.charAt(0)];
}
return [];
}
["assssssadaaaAAAasadaaab", "a", ""].forEach(s => {
s = s.toLowerCase();
console.log(writeInConsole(s))
});
Another example when you have multiple consecutive characters with the same length
function writeInConsole(s) {
let m = s.match(/(.)\1*/g);
if (m) {
let sorted = m.sort((a, b) => b.length - a.length)
let maxLength = sorted[0].length;
let result = [];
for (let i = 0; i < sorted.length; i++) {
if (sorted[i].length === maxLength) {
result.push([maxLength, sorted[i].charAt(0)]);
continue;
}
break;
}
return result;
}
return [];
}
[
"assssssadaaaAAAasadaaab",
"aaabccc",
"abc",
"yyzzz",
"aa",
""
].forEach(s => {
s = s.toLowerCase();
console.log(writeInConsole(s))
});
I'm no sure if this works for you:
string source = "/once/upon/a/time/";
int count = 0;
foreach (char c in source)
if (c == '/') count++;
The answer given by using regular expressions is more succinct, but since you say you are just starting out with programming, I will offer a verbose one that might be easier to follow.
var string = "assssssadaaaAAAasadaaab";
var string = string.toLowerCase();
function computeLongestRun(s) {
// we set up for the computation at the first character in the string
var longestRunLetter = currentLetter = string[0]
var longestRunLength = currentRunLength = 1
// loop through the string considering one character at a time
for (i = 1; i < s.length; i++) {
if (s[i] == currentLetter) { // is this letter the same as the last one?
currentRunLength++ // if yes, reflect that
} else { // otherwise, check if the current run
// is the longest
if (currentRunLength > longestRunLength) {
longestRunLetter = currentLetter
longestRunLength = currentRunLength
}
// reset to start counting a new run
currentRunLength = 1
currentLetter = s[i]
}
}
return [longestRunLetter, longestRunLength]
}
console.log(computeLongestRun(string))
Write a function that returns an integer indicating number of times a group of string "pzmcb" appears in a string in no particualr orther. for example
input string 1 -> "abdpsclmhz"
output 1 -> 1
input string 2 : pzmcbcbpzmpcm
output 2: 2
I have written the code but it is not efficient and cannot handle large input string. I will appreciate it if an efficent way of writing this function can be provided
'use strict';
//pmzcbpmzcbpmz [0 -4] [5 - 9] returns 2
function matchGroup(word) {
let regex = /[pzmcb]/g
let stringArray = word.match(regex);
//console.log(stringArray);
let cloneArray = [...stringArray];
let stored = [];
let searchString = "";
let secondString = "";
let temp = "";
let tempArray = [];
stringArray.forEach(item => {
if (cloneArray.indexOf(item) >= 0 && searchString.indexOf(item) === -1) {
searchString += item;
if (searchString.length === 5) {
stored.push(searchString);
searchString = "";
}
} else if(secondString.indexOf(item) === -1){
secondString += item;
if (secondString.length === 5) {
stored.push(searchString);
secondString = "";
}
}else {
temp += item;
if (temp.length === 5) {
tempArray.push(temp);
temp = "";
}
}
});
return stored.length;
// return integer
}
var paragraph = 'pzmcbpdfbcmz';
let result = matchGroup("abcdefpfklmhgzpzmcbpdfbcmzjklmoplzdsaklmcxheqgexcmpzdhgiwqertyhgdsbnmkjilopazxcsdertijuhgbdmlpoiqarstiguzcmnbgpoimhrwqasfgdhuetiopmngbczxsgreqad");
console.log(result);
I expect that the matchGroup function to return exact integers for large inputs
I'd build up a map of character counts:
function countChars(str) {
const count = {};
for(const char of str) count[char] = (count[char] || 0) + 1;
return count;
}
Now we can easily build up count maps of the string to find and the source:
const toFind = countChars("pzmbc"),
source = countChars("pzmcbpdfbcmz");
Now we can find the smallest relationship of chars to find and chars that are there:
const result = Math.min(
...Object.entries(toFind).map(([char, need]) => Math.floor((source[char] || 0) / need))
);
function countChar(char, string) {
return (string.match(new RegExp(char, "g")) || []).length;
}
function countDistinctSubstring(sub, string) {
firstChars = {};
for (i = 0; i < sub.length; i++) {
if (sub[i] in firstChars)
firstChars[sub[i]]++;
else
firstChars[sub[i]] = 1;
}
return Math.min(...Object.keys(firstChars).map(key => Math.floor(countChar(key, string) / firstChars[key])));
}
> countDistinctSubstring("pzmcb", "abdpsclmhz");
< 1
> countDistinctSubstring("pzmcb", "pzmcbcbpzmpcm");
< 2
> countDistinctSubstring("pzmcbpdfbcmz", "abcdefpfklmhgzpzmcbpdfbcmzjklmoplzdsaklmcxheqgexcmpzdhgiwqertyhgdsbnmkjilopazxcsdertijuhgbdmlpoiqarstiguzcmnbgpoimhrwqasfgdhuetiopmngbczxsgreqad");
< 3
I can't tell for sure, but I think this is what you are looking for. It counts the number of occurrences of each letter in the small string, then finds the minimum ratio of occurrences in the large string to those in the small string for each character. This minimum ratio is the maximum number of distinct times the small string can be composed of letters from the larger one.
Note that this answer was used in making the countChar function.
I'm trying to list all three letter permutations and this is the code I have -
window.permute = function(){
var alphabet = "abcdefghijklmnopqrstuvwxyz";
var searchTerm ="aaa";
var position = 2;
changeString(searchTerm, position);
}
window.changeString = function(searchTerm, position){
if (position <0){
alert(newString);
return;
}
var alphabet = "abcdefghijklmnopqrstuvwxyz"
for (j=0; j < 26;j++){
var newString = searchTerm.substr(0, position) + alphabet[j] + searchTerm.substr(position+1);
var newPosition = position -1;
changeString(newString,newPosition);
}
return;
}
It's not working and I'm not sure why- can anyone help?
var permutate = (function() {
var results = [];
function doPermute(input, output, used, size, level) {
if (size == level) {
var word = output.join('');
results.push(word);
return;
}
level++;
for (var i = 0; i < input.length; i++) {
if (used[i]) {
continue;
}
used[i] = true;
output.push(input[i]);
doPermute(input, output, used, size, level);
used[i] = false;
output.pop();
}
}
return {
getPermutations: function(input, size) {
var chars = input.split('');
var output = [];
var used = new Array(chars.length);
doPermute(chars, output, used, size, 0);
return results;
}
}
})();
for more information, visit http://jinwolf.tumblr.com/post/26476479113/draw-something-cheat
for an working example, check this jsfiddle http://jsfiddle.net/jinwolf/Ek4N5/31/
alert(newString);
newString is not defined right there. Instead, you should use the argument passed:
alert(searchTerm);
Edit: I'm not entirely sure of your approach. It seems overly complicated. This seems to work. I understand that you rather have your own code working, but perhaps this helps you in solving. I don't quite get your substr part.
http://jsfiddle.net/NUG2A/2/
var alphabet = "abc"; // shortened to save time
function permute(text) {
if(text.length === 3) { // if length is 3, combination is valid; alert
console.log(text); // or alert
} else {
var newalphabet = alphabet.split("").filter(function(v) {
return text.indexOf(v) === -1;
}); // construct a new alphabet of characters that are not used yet
// because each letter may only occur once in each combination
for(var i = 0; i < newalphabet.length; i++) {
permute(text + newalphabet[i]); // call permute with current text + new
// letter from filtered alphabet
}
}
}
permute("");
This will result in the following being called:
permute("");
permute("a");
permute("ab");
permute("abc"); // alert
permute("ac");
permute("acb"); // alert
permute("b");
// ...
I'm not sure from your question that you mean "permutations" because usually permutations do not include repeated elements where it looks like you want to include "aaa".
Here are several algorithms for listing permutations you can go check out. If it turns out you mean to have repetitions, it looks like pimvdb has you covered.
Edit: So you know what you are getting into run-time wise:
With repetition (aaa,aab,...): n^k = 26^3 = 17,576
Without repetition (abc,bac,...): n!/(n-k)! = 26!/(26-3)! = 15,600
for (j=0; j < 26;j++){
should be
for (var j=0; j<26; j++) {
Without the declaration, j is a global variable, so it only takes one iteration to get to 26 and then all the loops terminate.
For permutations a recursive algorith as pimvd showed is always nice but don't forget you can just brute force it with for-loops when N is small:
for(int x1=0; x1 < 26; x1++)
for(int x2=0; x2 < 26; x2++)
for(int x3=0; x3 < 26; x3++){
//do something with x1, x2, x3
}
In C#:
void DoPermuation(string s)
{
var pool = new HashSet<string>();
//Permute("", , pool);
pool = Permute(new List<char>(s));
int i = 0;
foreach (var item in pool) Console.WriteLine("{0:D2}: {1}", ++i, item);
}
HashSet<string> Permute(List<char> range)
{
if (range.Count == 1) return new HashSet<string>(new string[] { range[0].ToString() });
var pool = new HashSet<string>();
foreach (var c in range)
{
var list = new List<char>(range);
list.Remove(c);
foreach (var item in Permute(list)) pool.Add(c + item);
}
return pool;
}