I'm trying to answer a question on leetcode https://leetcode.com/problems/palindromic-substrings/. I know the passing solution is an O(N^2) solution with dynamic programming. All the solutions I've seen have used a bottom-up approach. I tried to use a top-down approach and I thought I also accomplished O(N^2) but the online judge is giving me time limit exceeded error at the final test case which made me unsure if my implementation is indeed O(N^2). Can someone please tell me the correct big O of the below code?
bool dfs(string s, int start, int end, string curWord, int &count, unordered_map<string, int> &map)
{
if (start >= end)
{
return true;
}
string st = to_string(start) + " , " + to_string(end);
if (map.find(st) != map.end())
return map[st];
if (s[start] == s[end] && dfs(s, start + 1, end - 1, curWord, count, map))
{
count++;
map[st] = true;
}
else
{
map[st] = false;
}
return map[st];
}
int countSubstrings(string s)
{
string word = "";
int count = 0;
unordered_map<string, int> map;
for (int i = 0; i < s.length(); i++)
{
for (int j = s.length() - 1; j > i; j--)
{
dfs(s, i, j, word, count, map);
}
}
return count + s.length();
}
Related
The following code gives the right output for finding the maximum number of consecutive 1's in a binary array. But time limit exceeds while compiling. Is there any where to reduce the time complexity of this code?
class Solution {
public:
int findMaxConsecutiveOnes(vector<int>& nums) {
int new_count = 0, count = 0;
if (find(nums.begin(), nums.end(), 1) == nums.end())
return 0;
for(int i=0; i<nums.size(); i++)
{
for(int j=i; j<nums.size()-1; j++)
{
if(nums[j] == 1 && nums[j+1] == 1)
count++;
else
break;
}
new_count = max(new_count, count+1);
count = 0;
}
return new_count;
}
};
Your solution is of time complexity O(N^2), where N is the size of nums.
The following one is a O(N) solution which get the answer in a single pass.
class Solution {
public:
int findMaxConsecutiveOnes(vector<int>& nums) {
int count = 0, max_count = 0;
for (auto num: nums) {
if (num == 1) {
count += 1;
} else {
max_count = max(count, max_count);
count = 0;
}
}
return max(count, max_count);
}
};
I'm doing the following problem (not homework):
I'm doing an exercise (not homework) and I decided to go with backtracking, The problem says as follows:
You are given as input a target string. Starting with an empty string,
you add characters to it, until your new string is same as the target.
You have two options to add characters to a string: You can append an
arbitrary character to your new string, with cost x You can clone any
substring of your new string so far, and append it to the end of your
new string, with cost y For a given target, append cost x, and clone
cost y, we want to know what the cheapest cost is of building the
target string
And some examples:
Target "aa", append cost 1, clone cost 2: the cheapest cost is 2:
Start with an empty string, ""
Append 'a' (cost 1), giving the string "a"
Append 'a' (cost 1), giving the string "aa"
Target "aaaa", append cost 2, clone cost 3: the cheapest cost is 7:
Start with an empty string, ""
Append 'a' (cost 2), giving the string "a"
Append 'a' (cost 2), giving the string "aa"
Clone "aa" (cost 3), giving the string "aaaa"
Target "xzxpzxzxpq", append cost 10, clone cost 11: the cheapest cost is 71:
Start with an empty string, ""
Append 'x' (cost 10): "x"
Append 'z' (cost 10): "xz"
Append 'x' (cost 10): "xzx"
Append 'p' (cost 10): "xzxp"
Append 'z' (cost 10): "xzxpz"
Clone "xzxp" (cost 11): "xzxpzxzxp"
Append 'q' (cost 10) : "xzxpzxzxpq"
So far so good. I first tried to do it with backtracking, but then the following test case came:
string bigString = "abcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcqaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjoirmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcqaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaip";
string doubleIt = bigString + bigString;
Now that's big.
Given costs of 1234, 1235 to append and clone respectivly, the total cost of building it is 59249.
So no more backtracking for this one because of the stack overflow.
I tried a more efficient approach:
#include <iostream>
#include <vector>
#include <string>
#include <set>
int isWorthClone(const int size, const std::string& target) {
int worth = 0;
for (int j = size; j < target.size() and worth < size; j++) {
if (target[j] == target[worth]) {
worth++;
}
else break;
}
return worth;
}
int buildSolution(const std::string& target, int cpyCst, int apndCst) {
int index = 0;
int cost = 0;
while (int(target.size()) != (index)) {
int hasta = isWorthClone(index, target);
if (cpyCst < hasta * apndCst) {
cost += cpyCst;
index += hasta ;
}
else {
cost += apndCst;
index++;
}
}
return cost;
}
int main() {
std::string bigString = "abcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcqaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjoirmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipiblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifpblgmbtmblgmbaipfdmbcntdblgblgmbaipmbcntdblgblgmbaipcbcntdblgblgmbaipobacjodblgblgmbaiabcblgmbcntdblgblgmbaipmbcntdblgblgmbaipfdmbcqaipfdmbcntdblgblgmbaipmbcntdblgblgmbaiprtifbcntdblgblgmbaipmbcntdblgblgmbaip";
std::string doubleIt = bigString + bigString;
std::string target = bigString;
int copyCost = 1235;
int appendCost = 1234;
std::cout << buildSolution(target, copyCost, appendCost) << std::endl;
}
but the output is 3588498, and from the test case, the correct output should be 59249.
I can't find why this approach is giving me that result. I tried debugging it, and it seems like isWorthClone is not finding the right position to clone in some cases. Also it seems a little strange, because it works for the other cases, but as this is somewhat "clone expensive" I think is propagating the error.
Any clues on why is this happening? This is O(n^2), so I think this should be the optimal solution.
Edit:
My code now looks like the following, trying to follow the dp approach:
int canCopy(const int i, const string& target, int posCopied) {
int iStartArray = 0;
bool canCopy = true;
int aux = i;
while (canCopy) {
if (aux - 1 + posCopied > target.size() or target[iStartArray] != target[aux - 1]) {
canCopy = false;
}
else {
posCopied += 1;
iStartArray++;
aux++;
}
}
return posCopied;
}
int stringConstruction(string target, int copyCost, int appendCost) {
vector<int> dp(target.size() + 1, std::numeric_limits<int>::max());
dp[1] = appendCost;
for (int i = 2; i < dp.size(); i++) {
dp[i] = std::min(dp[i], dp[i - 1] + appendCost);
int posCopied = canCopy(i, target, 0);
if (posCopied != 0 and (posCopied + i) < dp.size()) {
dp[posCopied + i] = dp[i] + copyCost;
}
}
return dp[dp.size()-1];
}
This still doesn't work for the test case presented here.
Edit2:
Finally I implemented the solution provided by #David Eisenstat (thanks!), with a really naive approach:
int best_clone(const string& s) {
int j = s.size() - 1;
while (s.substr(0, j).find(s.substr(j, s.size() - j)) != std::string::npos) {
j--;
}
return j + 1;
}
int stringConstruction(string target, int copyCost, int appendCost) {
vector<int> v = vector<int> (1, 0);
for (int i = 0; i < target.size(); i++) {
int cost = v[i] + appendCost;
int j = best_clone(target.substr(0, i+1));
if (j <= i) {
cost = std::min(cost, v[j] + copyCost);
}
v.push_back(cost);
}
return v[v.size() - 1];
}
It seems like I missunderstood the problem. This is giving the solution for the test cases, but it takes too long. best_clone needs to be optimized.
Edit 3:
(Hope this is the last one)
I added the following class SA for storing the suffix array:
#pragma once
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <chrono>
using namespace std;
typedef struct {
int index;
string s;
} suffix;
struct comp
{
inline bool operator() (const suffix& s1, const suffix& s2)
{
return (s1.s < s2.s);
}
};
class SA
{
private:
vector<suffix> values;
public:
SA(const string& s) : values(s.size()) {
string aux = s;
for (int i = 0; i < s.length(); i++) {
values[i].index = i;
values[i].s = s.substr(i, s.size() - i);;
}
sort(values.begin(), values.end(), comp());
}
friend ostream& operator<<(ostream& os, const SA& dt)
{
for (int i = 0; i < dt.values.size(); i++) {
os << dt.values[i].index << ": " << dt.values[i].s << "\n";
}
return os;
}
int search(const string& subst, int i, int j) {
while (j >= i) {
int mid = (i + j) / 2;
if (this->values[mid].s > subst) {
j = mid-1;
}
else if (this->values[mid].s < subst) {
i = mid+1;
}
else return mid;
}
return -1;
}
};
But know I don't know how to search here for the best clone in this array. (I know this is slow, n*2log(n) I would say, but I think is going to be good enough for this one. So now I need to put together these parts.
The problem is that you're making the decision to clone greedily. Let's look at a case where the append cost is 2 and the clone cost is 3. If you process the string aabaaaba, you'll append aab, clone aa, and clone aba, whereas the best solution is to append aaba and clone it.
The fix is dynamic programming, specifically, to build an array of the cost to make each prefix of the target string. To fill each entry, take the min of (append cost plus previous entry, clone cost plus cost for the shortest prefix that can be completed with one clone). Since the clone cost is constant, the array is nondecreasing, and therefore we don't need to check all of the possible prefixes.
Depending on the constraints you may need to construct a suffix array/longest common prefix array (using e.g., SA-IS) to identify all of the best clones quickly. This will run in time o(n²) for sure (quite possibly O(n), but there are enough moving parts that I don't want to claim that).
This Python is too slow but gets the right answer on the large test case:
def best_clone(s):
j = len(s) - 1
while s[j:] in s[:j]:
j -= 1
return j + 1
def construction_cost(s, append_cost, clone_cost):
table = [0]
for i in range(len(s)):
cost = table[i] + append_cost
j = best_clone(s[: i + 1])
if j <= i:
cost = min(cost, table[j] + clone_cost)
table.append(cost)
return table[len(s)]
If the limit of your ambitions is quadratic, then we can put the Z function for string matching to good use.
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
using Cost = unsigned long long;
// Adapted from https://cp-algorithms.com/string/z-function.html
std::vector<std::size_t> ZFunction(std::string_view s) {
std::size_t n = s.length();
std::vector<std::size_t> z(n);
for (std::size_t i = 1, l = 0, r = 0; i < n; i++) {
if (i <= r) {
z[i] = std::min(r - i + 1, z[i - l]);
}
while (i + z[i] < n && s[z[i]] == s[i + z[i]]) {
z[i]++;
}
if (i + z[i] - 1 > r) {
l = i;
r = i + z[i] - 1;
}
}
return z;
}
std::size_t BestClone(std::string_view s) {
std::string r{s};
std::reverse(r.begin(), r.end());
auto z = ZFunction(r);
std::size_t best = 0;
for (std::size_t i = 0; i < z.size(); i++) {
best = std::max(best, std::min(z[i], i));
}
return s.length() - best;
}
Cost ConstructionCost(std::string_view s, Cost append_cost, Cost clone_cost) {
std::vector<Cost> costs = {0};
for (std::size_t j = 0; j < s.length(); j++) {
std::size_t i = BestClone(s.substr(0, j + 1));
if (i <= j) {
costs.push_back(
std::min(costs.back() + append_cost, costs[i] + clone_cost));
} else {
costs.push_back(costs.back() + append_cost);
}
}
return costs.back();
}
int main() {
std::string s;
while (std::cin >> s) {
std::cout << ConstructionCost(s, 1234, 1235) << '\n';
}
}
I am writing a backtracking algorithm, I think my writing is correct, but the output is wrong. I went to debug and found that the execution:When the program executes to this sentence in the for loop, sometimes it directly skips the following statement in the for loop.
Question is here:
Permutation Sequence
I have written a debugging environment, which can be run directly.
My answer is here:
class Solution {
public:
int index = 0, N, K;
string ans;
string getPermutation(int n, int k) {
N = n;
K = k;
string str;
backtrace(str, 0);
return ans;
}
void backtrace(string &str, int start) {
if (start == N) {
index++;
if (index == K) {
ans = str;
}
return;
}
for (int i = start; i < N; i++) {
if (index == K) {
return;
}
string temp = str; //For loop to this sentence will not execute the following statement
str += to_string(i + 1);
backtrace(str, i + 1);
str = temp;
}
}
};
int nn(int n) {
if (n == 1) {
return 1;
}
return nn(n - 1) * n;
}
int main() {
Solution so;
for (int i = 1; i <= nn(3); i++) {
cout << so.getPermutation(3, i) << endl;
}
system("pause");
}
I’m not sure if it’s the c++ problem or mine, or it might be my algorithm,but I’ve checked it many times.
My previous thinking was wrong,#Igor Tandetnik remended me . This problem requires a bit of mathematical skills or it will time out. Thanks for your help #john and #Igor Tandetnik.
My finally code is here:
class Solution {
private:
vector<int> hash;
vector<int> factorial;
bool flag = true;
void dfs(int cur, int n, int &k, string &ret, int &cnt, string path){
if(cur == n){
ret = path;
flag = false;
return;
}
int temp = factorial[n-cur-1];
for(int i=0; i<n; i++){
if(hash[i] && flag){
if(temp < k ){
k = k - temp;
continue;
}
path.push_back(i+1+'0');
hash[i] = 0;
dfs(cur+1,n,k,ret,cnt,path);
hash[i] = 1;
path.pop_back();
}
}
}
public:
string getPermutation(int n, int k) {
//calculate the factorial
if(n == 1) return "1";
factorial.resize(n);
factorial[0] = 1;
factorial[1] = 1;
if(n > 2){
for(int i=2; i<n; i++){
factorial[i] = i * factorial[i-1];
}
}
string ret;
string path;
hash.resize(n,1);
int cnt = 0;
dfs(0,n,k,ret,cnt,path);
return ret;
}
};
Assuming n = 4, k = 17, we can know that the 17th permutation is [3,4,1,2]. In order to find it, we need to do pruning at key nodes. How to judge? As shown in the figure, when we start the search, we visit the purple node "1", and notice that if we continue to visit (deep search) at this time, it is actually meaningless, because there are at most 3 from this node! =6 full permutations and combinations, and what we are looking for is the 17th, 6<17, so we prun directly; visit the purple node "2", the same thing can be seen, you need pruning at this node; visit the purple node "3" ", now that the conditions are met, 6> 5, you need to search down. (Note here that a simple counting technique is that when a node needs to be pruned, we need to update the value of k, k = k-the node corresponds to the factorial number).
Author: edward_wang
This is a leetcode question about " Longest Substring Without Repeating Characters"
and I failed on 987th (It is the final test case)
the reason i fail is because "Time Limit Exceeded"
Can someone give me some advice to fix my code?
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<char> answer;
vector<char> temp;
int len = s.length();
for ( int a = 0; a < len;a++ ){
for( int aa = a; aa < len;aa++ ){
temp.push_back(s[aa]) ;
if ( repeat(temp) ){
temp.pop_back();
changeAnswer(temp,answer);
temp.clear();
aa = len;
}
changeAnswer(temp,answer);
}
}
return answer.size();
}
bool repeat(vector<char> temp){
if ( temp.size() < 2 )
return false;
for ( int a = 0; a < temp.size();a++ )
for ( int aa = a+1; aa < temp.size(); aa++ )
if ( temp[aa] == temp[a] )
return true;
return false;
}
void changeAnswer( vector<char> &temp, vector<char> &answer ){
if ( temp.size()>answer.size() )
answer = temp;
}
};
It looks that you are using a complete brute force approach to solve the question. The time complexity of your solution is O(n^2), if 'n' is the length of the string. In the case of string length being in range 10^5, the time limit will definitely exceed. First, you should try to optimize your code to make it work in O(n) time.
Here is what you can do:
I think hashing would be helpful in this case. You can store the last occurrence of a character in a hashMap or unordered_map and check the current character if it is already there in the map. If so, you need to count only the characters after the last occurrence of this character. To keep track of from where you have to count the characters simply maintain a variable that stores the first index of a substring with unique characters(like 'p' that I have used in the code below).
Here is my implementation of the above:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> mp;
int n = (int)s.length();
if(n == 0){
return 0;
}
int res = 1;
int p = 0;
mp[s[0]] = 0;
for(int i = 1; i < n ; i++){
if(mp.find(s[i]) == mp.end()){
res = max(res, i-p+1);
mp[s[i]] = i;
}
else{
char ch = s[i];
int temp = mp[ch];
if(p <= temp)
p = temp + 1;
res = max(res, i - p + 1);
mp[ch] = i;
}
}
return res;
}
Try this, it should work.
I was trying to solve the 3 sum problem in cpp.
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
vector<vector<int>> result;
for (int i = 0; i < size - 2; ++i) {
for (int j = i + 1; j < size - 1; ++j) {
for (int k = j + 1; k < size; ++k) {
if (sumToZero(i, j, k, nums)) {
vector<int> newComb = vectorify(i, j, k, nums);
//printComb(newComb);
if (!exist(newComb, result)) {
//cout << "not exist" << endl;
result.push_back(newComb);
} else {
//cout << "exist" << endl;
}
}
}
}
}
return result;
}
bool sumToZero(int i, int j, int k, vector<int>& nums) {
return nums[i] + nums[j] + nums[k] == 0;
}
vector<int> vectorify(int i, int j, int k, vector<int>& nums) {
vector<int> result;
result.push_back(nums[i]);
result.push_back(nums[j]);
result.push_back(nums[k]);
return result;
}
void printComb(vector<int>& input) {
cout << input[0] << input[1] << input[2] << endl;
}
bool isSameComb(vector<int>& a, vector<int> b) {
for (int i = 0; i < b.size(); ++i) {
if (a[0] == b[i]) {
b.erase(b.begin() + i);
}
}
for (int i = 0; i < b.size(); ++i) {
if (a[1] == b[i]) {
b.erase(b.begin() + i);
}
}
for (int i = 0; i < b.size(); ++i) {
if (a[2] == b[i]) {
b.erase(b.begin() + i);
}
}
return b.empty();
}
bool exist(vector<int>& niddle, vector<vector<int>>& haystack) {
int size = haystack.size();
for (int i = 0; i < size; ++i) {
if (isSameComb(niddle, haystack[i])) {
return true;
}
}
return false;
}
};
However, this solution exceeded the time limit. I cannot think of the source of extra complexity. Can someone help me point out where am I doing extra computation?
You can be in O(n²) with something like:
std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {
std::sort(nums.begin(), nums.end());
std::vector<std::vector<int>> res;
for (auto it = nums.begin(); it != nums.end(); ++it) {
auto left = it + 1;
auto right = nums.rbegin();
while (left < right.base()) {
auto sum = *it + *left + *right;
if (sum < 0) {
++left;
} else if (sum > 0) {
++right;
} else {
res.push_back({*it, *left, *right});
std::cout << *it << " " << *left << " " << *right << std::endl;
++left;
++right;
}
}
}
return res;
}
Demo
I let duplicate handling as exercise.
The source of extra complexity is the third loop, which brings time complexity of your code to O(n3).
Key observation here is that once you have two numbers, the third number is fixed, so you do not need to loop around to find it: use hash table to see if it's there or not in O(1). For example, if your first loop looks at value 56 and your second loop looks at value -96, the third value must be 40 in order to yield zero total.
If the range of numbers is reasonably small (say, -10000..10000) you can use an array instead.
This would bring time complexity to O(n2), which should be a noticeable improvement on timing.
A couple of possibilities:
First, construct a hash table of all entries in the vector up front, then remove the third loop. Inside the second loop, simply check whether -nums[i] - nums[j] exists in the hash table. That should bring your time complexity from O(n3) back to something closer to O(n2).
Second, function calls aren't free though an optimiser can sometimes improve that considerably. There's no performance reason why you should be calling a function to check if three numbers add to zero so you could replace:
if (sumToZero(i, j, k, nums)) {
with:
if (nums[i] + nums[j] == -nums[k]) {
Of course, this is rendered moot if you adopt the first suggestion.
Third, don't check and insert the possible result every time you get one. Just add it to the vector no matter what. Then, at the end, sort the vector and remove any duplicates. That should hopefully speed things up a bit as well.
Fourth, there's quite possibly a performance hit for using a vector for the potential result when an int[3] would do just as well. Vectors are ideal if you need something with a variable size but, if both the minimum and maximum size of an array-type collection is always going to be a fixed value, raw arrays are fine.
But perhaps the most important advice is measure, don't guess!
Make sure that, after each attempted optimisation, you test to see whether it had a detrimental, negligible, or beneficial effect. A test suite of various data sets, and automating the process, will make this much easier. But, even if you have to do it manually, do so - you can't improve what you can't measure.
Here is my solution that finds all unique triplets in O(n^2) run-time.
class Solution {
public: vector<vector<int>> threeSum(vector<int>& nums) {
int len = nums.size();
if(len<3) return {};
sort(nums.begin(), nums.end());
vector<vector<int>> retVector;
int target, begin, end;
int i=0;
while(i < len - 2)
{
int dup; // to find duplicates entries
target = -nums[i];
begin = i + 1; end = len - 1;
while (begin < end)
{
if (nums[begin] + nums[end] < target) begin++;
else if (nums[begin] + nums[end] > target) end--;
else
{
retVector.push_back({nums[i], nums[begin], nums[end]});
// its time to remove duplicates
dup=nums[begin];
do begin++; while(nums[begin] == dup); // removing from front
dup=nums[end];
do end--; while(nums[end] == dup); // removing from back
}
}
dup=nums[i];
do i++; while(nums[i] == dup) ; // removing all ertries same as nums[i]
}
return retVector;
}
};