WHY I am getting a TLE? - algorithm

PROBLEM: I am getting a TLE in this LEETCODE problem of finding the longest common subsequence. with 42/45 test cases being passed. please help. YOU CAN COPY PASTE BELOW CODE ON LEETCODE 1143 PROBLEM and help if possible:
//solve(i,j)-->represents length of LCS till index i and j in string text1 and text2 respectively.
int solve(string text1, string text2,int i,int j,int dp[1001][1001]){
//base case
if(i<0||j<0){
return 0 ;
}
if(dp[i][j]!=-1) {
return dp[i][j];
}
else{
if(text1[i]==text2[j]){
return dp[i][j] = 1+ solve(text1,text2,i-1,j-1,dp) ;
}
else{
return dp[i][j] = max(solve(text1,text2,i,j-1,dp),solve(text1,text2,i-1,j,dp));
}
}
}
int longestCommonSubsequence(string text1, string text2) {
int m=text1.size();
int n=text2.size();
int dp[1001][1001];
memset(dp,-1,sizeof(dp));
return solve(text1,text2,m-1,n-1,dp);
}

Reason for TLE is that solve recursion is not efficient. Recursion is happening twice (here: max(solve(text1,text2,i,j-1,dp),solve(text1,text2,i-1,j,dp))). Try to find a more efficient algorithm.
Instead of recursion I would just iterate through the matrix, only not by row or by column, but by diagonal.
Minor improvement would be to pass strings by reference (so string& instead of just string).

Related

Count of subsetsum problem, how to debug where the solution is not working?

So I'm trying to solve this problem :
Given an array arr[] of integers and an integer sum, the task is to
count all subsets of the given array with a sum equal to a given sum.
Note: Answer can be very large, so, output answer modulo 10^9+7
Now this is the solution I'm trying out here:
class Solution{
private:
vector<vector<int>> t;
public:
Solution() {
t.resize(1001, vector<int> (1001,-1));
}
int perfectSum(int arr[], int n, int sum)
{
long long int result = fmod(sumrecursive(arr, n, sum),(pow(10,9)+7));
return result;
}
long long int sumrecursive(int arr[], int n, int sum){
if(sum==0){
return 1;
}
if(n==0){
return 0;
}
if(t[n][sum] != -1){
return t[n][sum];
}
if(arr[n-1]>sum){
return t[n][sum] = sumrecursive(arr, n-1, sum);
} else {
return t[n][sum] = sumrecursive(arr,n-1, sum-arr[n-1]) + sumrecursive(arr, n-1, sum);
}
}
};
Now this code is not working after some certain input:
I don't know on how to proceed in solving this problem at this point. Ideally according to the code I have written the input is within the grasp of the code and output should've been correct but unfortunately it is not the case. I wanted to ask if someone could spot on where the problem might be in the code or guide me on how to debug where the problem is in the code.
You are probably encountering integer overflow along the way.
You are taking the mod only right before ending the function, but your cache is of type int, so when placing too big numbers - you are losing some data due to overflow.

Time complexity of prefix to postfix conversion?

I think it should be quadratic i.e O(n^2). I am reading from this source prefix to postfix . I assume that appending two string takes linear time (O(sum of size of the two strings which we are appending)) and maximum number of times we need to append can go upto O(n) and thus overall complexity is O(n^2).
Can some one tell if i am wrong and can some one provide better proof of this ?
Yes, you're right that it's O(n2), and I think your proof is OK, but that depends who you have to prove it to. Maybe show explicitly how to construct a string that would result in O(n) appends of O(n) size.
Here's a simple recursive version that does the job in O(n):
static String preToPost(String src)
{
StringBuilder dest = new StringBuilder(src.length());
for(int pos=0; pos < src.length(); pos = preToPost(dest, src, pos));
return dest.toString();
}
// Convert one prefix expression to postfix. Returns
// end position
static int preToPost(StringBuilder dest, String src, int pos)
{
if (pos >= src.length())
{
//no expression
return pos;
}
char c = src.charAt(pos++);
if ("+-/*".indexOf(c)>=0)
{
//operator. Convert both operands first
pos = preToPost(dest, src, pos);
pos = preToPost(dest, src, pos);
}
dest.append(c);
return pos;
}
The iterative version is not much more complicated:
static String preToPost2(String src)
{
StringBuilder dest = new StringBuilder(src.length());
int pos=0;
Stack<Character> stk = new Stack<>();
while(pos < src.length())
{
char c = src.charAt(pos++);
if ("+-/*".indexOf(c)>=0)
{
//operator. After the next 2 expressions, put c
stk.push(c);
//after the next expression, just do another one
stk.push('\0');
continue;
}
dest.append(c);
// done expression. check the todo stack
while(!stk.empty())
{
c = stk.pop();
if (c=='\0')
{
break;
}
dest.append(c);
// the append completed another expression, so loop
// to check the todo stack again
}
}
return dest.toString();
}
This is a direct conversion of the recursive one.

find permutation of an array with duplicates. Why pass by value in recursion (C++ implementation)

There are different ways to find all permutation of an integer array with duplicates. Here I only talk about the recursive method without using an additional "visited[]" array.
There correct way to do it is:
void helper(vector<vector<int>>& ans, vector<int> nums, int pos) {
if(pos == nums.size()-1) {
ans.push_back(nums);
return;
}
for(int i = pos; i < nums.size(); i++) {
if(i == pos || nums[i] != nums[pos]) {
swap(nums[i], nums[pos]);
helper(ans, nums, pos+1);
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
helper(ans, nums, 0);
return ans;
}
It is not so clear to me why it passes nums[] as a copy into the recursive function. So I looked around and on geeks for geeks , it says that "The idea is to fix the first character at first index and recursively call for other subsequent indexes". I was thinking that I can fix the first character then recursively call for the other subsequent indexes by passing nums[] as reference and "swap back" when recursion is done (as below). But unfortunately it did not work.
void helper(vector<vector<int>>& ans, vector<int>& nums, int pos) {
if(pos == nums.size()-1) {
ans.push_back(nums);
return;
}
for(int i = pos; i < nums.size(); i++) {
if(i == pos || nums[i] != nums[i-1]) {
swap(nums[i], nums[pos]);
helper(ans, nums, pos+1);
swap(nums[i], nums[pos]);
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
helper(ans, nums, 0);
return ans;
}
I am wondering what is wrong when passing nums[] as reference into recursion? Why passing nums[] by copy into recursion is correct?
I think I found the reason. Passing by value and passing by reference give two totally different algorithms. To understand that. Let's first note two important observations:
The first thing we did is to sort the array, why? because we want that all the permutations are visited in the "next permutation" order, i.e. 123, 132, 213, 231, 312, 321. So that there will be no duplicates.
The subproblem in the next recursion also maintained the sorted property. Let's use an example to illustrate this.
Input nums = [1,2,2,3] passing by value to recursion, with pos = 0,
i = 0: subproblem is [2,2,3],
i = 1: subproblem is [1,2,3],
i = 2: skipped,
i = 3 subproblem is [1,2,2].
All the subproblems in this level of recursion are all SORTED.
But if [1,2,2,3] is passed by reference, the subproblems are NOT sorted, so you can not reply on "next permutation" method to give you non-duplicated permutations.
If you are still confused, please take some time to read through this discussion:
https://discuss.leetcode.com/topic/8831/a-simple-c-solution-in-only-20-lines/28?page=2

find number of 1s in a 0-1 array with all 1s “on the left”?

An array consists N many 1's and 0's, all 1's come before any 0's. Find no of 1's in the array. It is clear that with binary search it is O(log N). Is there an algorithm do this in O(log(number of 1's)) time?
You can actually do it in O(lg m) time, where m is the number of 1s. I won't give the entire algorithm since this looks like homework, but here's a hint: try to "reverse" a binary search so that it expands the search area rather than contracting it.
If you just iterate over this array, you count all 1's and finally find 0 you made N+1 steps so it's O(n+1) algorith in my opinion.
class OneZero
{
public static int binary_search (byte[] array, int start, int end, int value)
{
if (end <= start) return -1;
if (Math.floor((start+end)/2) == value) return Math.floor((start+end)/2);
return binary_search (array, start, Math.floor((start+end)/2)-1, value);
}
public static int nbOfOnes (byte[] array, int value)
{
return (binary_search(array, 0, array.length,value)+1);
}
public static void main ()
{
byte[] arr = { 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 };
System.out.println(" number of 1s is: "+nbOfOnes(arr,1));
}
}

Longest common prefix for n string

Given n string of max length m. How can we find the longest common prefix shared by at least two strings among them?
Example: ['flower', 'flow', 'hello', 'fleet']
Answer: fl
I was thinking of building a Trie for all the string and then checking the deepest node (satisfies longest) that branches out to two/more substrings (satisfies commonality). This takes O(n*m) time and space. Is there a better way to do this
Why to use trie(which takes O(mn) time and O(mn) space, just use the basic brute force way. first loop, find the shortest string as minStr, which takes o(n) time, second loop, compare one by one with this minStr, and keep an variable which indicates the rightmost index of minStr, this loop takes O(mn) where m is the shortest length of all strings. The code is like below,
public String longestCommonPrefix(String[] strs) {
if(strs.length==0) return "";
String minStr=strs[0];
for(int i=1;i<strs.length;i++){
if(strs[i].length()<minStr.length())
minStr=strs[i];
}
int end=minStr.length();
for(int i=0;i<strs.length;i++){
int j;
for( j=0;j<end;j++){
if(minStr.charAt(j)!=strs[i].charAt(j))
break;
}
if(j<end)
end=j;
}
return minStr.substring(0,end);
}
there is an O(|S|*n) solution to this problem, using a trie. [n is the number of strings, S is the longest string]
(1) put all strings in a trie
(2) do a DFS in the trie, until you find the first vertex with more than 1 "edge".
(3) the path from the root to the node you found at (2) is the longest common prefix.
There is no possible faster solution then it [in terms of big O notation], at the worst case, all your strings are identical - and you need to read all of them to know it.
I would sort them, which you can do in n lg n time. Then any strings with common prefixes will be right next to eachother. In fact you should be able to keep a pointer of which index you're currently looking at and work your way down for a pretty speedy computation.
As a completely different answer from my other answer...
You can, with one pass, bucket every string based on its first letter.
With another pass you can sort each bucket based on its second later. (This is known as radix sort, which is O(n*m), and O(n) with each pass.) This gives you a baseline prefix of 2.
You can safely remove from your dataset any elements that do not have a prefix of 2.
You can continue the radix sort, removing elements without a shared prefix of p, as p approaches m.
This will give you the same O(n*m) time that the trie approach does, but will always be faster than the trie since the trie must look at every character in every string (as it enters the structure), while this approach is only guaranteed to look at 2 characters per string, at which point it culls much of the dataset.
The worst case is still that every string is identical, which is why it shares the same big O notation, but will be faster in all cases as is guaranteed to use less comparisons since on any "non-worst-case" there are characters that never need to be visited.
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0)
return "";
char[] c_list = strs[0].toCharArray();
int len = c_list.length;
int j = 0;
for (int i = 1; i < strs.length; i++) {
for (j = 0; j < len && j < strs[i].length(); j++)
if (c_list[j] != strs[i].charAt(j))
break;
len = j;
}
return new String(c_list).substring(0, len);
}
It happens that the bucket sort (radix sort) described by corsiKa can be extended such that all strings are eventually placed alone in a bucket, and at that point, the LCP for such a lonely string is known. Further, the shustring of each string is also known; it is one longer than is the LCP. The bucket sort is defacto the construction of a suffix array but, only partially so. Those comparisons that are not performed (as described by corsiKa) indeed represent those portions of the suffix strings that are not added to the suffix array. Finally, this method allows for determination of not just the LCP and shustrings, but also one may easily find those subsequences that are not present within the string.
Since the world is obviously begging for an answer in Swift, here's mine ;)
func longestCommonPrefix(strings:[String]) -> String {
var commonPrefix = ""
var indices = strings.map { $0.startIndex}
outerLoop:
while true {
var toMatch: Character = "_"
for (whichString, f) in strings.enumerate() {
let cursor = indices[whichString]
if cursor == f.endIndex { break outerLoop }
indices[whichString] = cursor.successor()
if whichString == 0 { toMatch = f[cursor] }
if toMatch != f[cursor] { break outerLoop }
}
commonPrefix.append(toMatch)
}
return commonPrefix
}
Swift 3 Update:
func longestCommonPrefix(strings:[String]) -> String {
var commonPrefix = ""
var indices = strings.map { $0.startIndex}
outerLoop:
while true {
var toMatch: Character = "_"
for (whichString, f) in strings.enumerated() {
let cursor = indices[whichString]
if cursor == f.endIndex { break outerLoop }
indices[whichString] = f.characters.index(after: cursor)
if whichString == 0 { toMatch = f[cursor] }
if toMatch != f[cursor] { break outerLoop }
}
commonPrefix.append(toMatch)
}
return commonPrefix
}
What's interesting to note:
this runs in O^2, or O(n x m) where n is the number of strings and m
is the length of the shortest one.
this uses the String.Index data type and thus deals with Grapheme Clusters which the Character type represents.
And given the function I needed to write in the first place:
/// Takes an array of Strings representing file system objects absolute
/// paths and turn it into a new array with the minimum number of common
/// ancestors, possibly pushing the root of the tree as many level downwards
/// as necessary
///
/// In other words, we compute the longest common prefix and remove it
func reify(fullPaths:[String]) -> [String] {
let lcp = longestCommonPrefix(fullPaths)
return fullPaths.map {
return $0[lcp.endIndex ..< $0.endIndex]
}
}
here is a minimal unit test:
func testReifySimple() {
let samplePaths:[String] = [
"/root/some/file"
, "/root/some/other/file"
, "/root/another/file"
, "/root/direct.file"
]
let expectedPaths:[String] = [
"some/file"
, "some/other/file"
, "another/file"
, "direct.file"
]
let reified = PathUtilities().reify(samplePaths)
for (index, expected) in expectedPaths.enumerate(){
XCTAssert(expected == reified[index], "failed match, \(expected) != \(reified[index])")
}
}
Perhaps a more intuitive solution. Channel the already found prefix out of earlier iteration as input string to the remaining or next string input. [[[w1, w2], w3], w4]... so on], where [] is supposedly the LCP of two strings.
public String findPrefixBetweenTwo(String A, String B){
String ans = "";
for (int i = 0, j = 0; i < A.length() && j < B.length(); i++, j++){
if (A.charAt(i) != B.charAt(j)){
return i > 0 ? A.substring(0, i) : "";
}
}
// Either of the string is prefix of another one OR they are same.
return (A.length() > B.length()) ? B.substring(0, B.length()) : A.substring(0, A.length());
}
public String longestCommonPrefix(ArrayList<String> A) {
if (A.size() == 1) return A.get(0);
String prefix = A.get(0);
for (int i = 1; i < A.size(); i++){
prefix = findPrefixBetweenTwo(prefix, A.get(i)); // chain the earlier prefix
}
return prefix;
}

Resources