What is the time complexity of the longestPalindrome function in the following code? - time-complexity

size_t length(const pair<size_t, size_t>& pos) {
return pos.second - pos.first;
}
pair<size_t, size_t> longestPalindrome(const string& s, size_t start, size_t end, map<pair<size_t, size_t>, pair<size_t, size_t>>& memo) {
if (memo.find({start, end}) != memo.end()) {
return memo[{start, end}];
}
if (end - start == 1) {
return {start, end};
}
if (end - start == 2) {
if (s[start] == s[end - 1]) {
return {start, end};
}
return {start, end - 1};
}
if (s[start] == s[end - 1]) {
auto p = longestPalindrome(s, start + 1, end - 1, memo);
if (p.first == (start + 1) && p.second == (end - 1)) {
return memo[{start, end}] = {start, end};
}
}
auto p1 = longestPalindrome(s, start + 1, end, memo);
auto p2 = longestPalindrome(s, start, end - 1, memo);
return memo[{start, end}] = (length(p1) > length(p2) ? p1 : p2);
}
The above function finds the longest substring that is also a palindrome.
Given a string, the code starts with two pointers: one at the start, and one at the end. If the character on these two positions are not the same, longestPalindrome recursively calls itself, once by incrementing start and once by decrementing end.
If it were not for the memoization, the function would have been O(2^n). But now that I'm using a memo, what is the time complexity of this code?

Related

Function don't exit with return kotlin

I wrote this function with recursion in Kotlin, it's just for academic purposes.
But I have a problem, when the condition is true, the execution is not interrupted. It's as if it ignores the return command and keeps iterating.
I have seen it in debug, that when the condition is true it goes through there and then continues.
Anyone knows how to solve this?
In this capture, see the debugger in the return true statement, but the function don't exit.
Here is the function:
// The inputArray must be sorted in order to apply the binary search.
fun binarySearch(inputArray: Array<Int>, itemToSearch: Int) : Boolean {
// This print is for see the interactions in the search
println()
inputArray.forEach {
print("$it,")
}
if (inputArray.size > 1) {
if (itemToSearch == inputArray[(inputArray.size / 2) - 1]) {
return true
}
if (itemToSearch > inputArray[(inputArray.size / 2) - 1]) {
binarySearch(inputArray.copyOfRange(inputArray.size / 2, inputArray.size), itemToSearch)
} else {
binarySearch(inputArray.copyOfRange(0, inputArray.size / 2), itemToSearch)
}
}
return false
}
Here is the call:
val result = binarySearch(arrayOf(1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23), 16)
You need to return the result of the recursion, like
return binarySearch(inputArray.copyOfRange(inputArray.size / 2, inputArray.size), itemToSearch)
so in total:
// The inputArray must be sorted in order to apply the binary search.
fun binarySearch(inputArray: Array<Int>, itemToSearch: Int) : Boolean {
// This print is for see the interactions in the search
println()
inputArray.forEach {
print("$it,")
}
if (inputArray.size > 1) {
if (itemToSearch == inputArray[(inputArray.size / 2) - 1]) {
return true
}
if (itemToSearch > inputArray[(inputArray.size / 2) - 1]) {
return binarySearch(inputArray.copyOfRange(inputArray.size / 2, inputArray.size), itemToSearch)
} else {
return binarySearch(inputArray.copyOfRange(0, inputArray.size / 2), itemToSearch)
}
}
return false
}

Roman Numerals. Could you point out my mistakes further down the road?

Beginner here. This piece of code converts number into roman numerals in multiples of 50 if not 10 if not 9 and down to 0. Methods are so intertwined. Is there something (just at a glance) you could suggest I should avoid doing? Thank You.
public static void main(String[] args) {
System.out.println(fiftyAndAbove(37));
}
public static String nineAndDown(int number) {
String one = "I", five = "V", ten = "X", sum = "";
if(number == 5) {
return five;
} else if(number == 9) {
return one + ten;
}
else if(number > 5) {
for(int i=1; i<=number-5; i++) {
sum += one;
}
return five + sum;
} else {
if(number == 4 ) {
return one + five;
} else
for(int i=1; i <=number; i++) {
sum += one;
}
} return sum;
}
public static String tenAndAbove(int number) {
int remainder = number % 10, numberOftens = number/10;
String ten = "X", sum = "";
if(numberOftens > 0) {
while(numberOftens > 0) {
sum += ten;
numberOftens -= 1;
}
}
return sum + nineAndDown(remainder);
}
public static String fiftyAndAbove(int number) {
int remainder = number % 50, numberOfFifty = number/50;
String fifty = "L", sum = "";
if(numberOfFifty > 0) {
while(numberOfFifty > 0) {
sum += fifty;
numberOfFifty -= 1;
}
}
return sum + tenAndAbove(remainder);
}
Is there something (just at a glance) you could suggest I should avoid doing?
I'd not unnecessarily complicate the logic as with
if(numberOfFifty > 0) {
while(numberOfFifty > 0) {
…
}
}
which is equivalent to
while (numberOfFifty > 0)
{
…
}
You could also have a look at this implementation and see what you prefer:
import java.util.Arrays;
…
public static String fiftyAndAbove(int number)
{
int remainder = number%50, numberOfFifty = number/50;
char [] Ls = new char [numberOfFifty];
Arrays.fill(Ls, 'L');
return new String(Ls) + tenAndAbove(remainder);
}
You have four places like this in your program where you need a string of a character repeated. If you're willing to require a certain Java version or above, you can also use one of the methods described at Java: String - add character n-times; otherwise I'd suggest to use a function to do it.
You could also think about whether you find
String one = "I", five = "V", ten = "X", sum = "";
if(number == 5) {
return five;
} else if(number == 9) {
return one + ten;
}
really better than
if (number == 5) return "V";
if (number == 9) return "IX";

How to count letter differences of two strings in bigquery?

For example i have:
1: 6c71d997ba39
2: 6c71d997d269
I need to get 4.
You can consider using Levenshtein distance for your use-case
the Levenshtein distance is a string metric for measuring the difference between two sequences. Informally, the Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other
Below example is for BigQuery Standard SQL
#standardSQL
CREATE TEMPORARY FUNCTION EDIT_DISTANCE(string1 STRING, string2 STRING)
RETURNS INT64
LANGUAGE js AS """
var _extend = function(dst) {
var sources = Array.prototype.slice.call(arguments, 1);
for (var i=0; i<sources.length; ++i) {
var src = sources[i];
for (var p in src) {
if (src.hasOwnProperty(p)) dst[p] = src[p];
}
}
return dst;
};
var Levenshtein = {
/**
* Calculate levenshtein distance of the two strings.
*
* #param str1 String the first string.
* #param str2 String the second string.
* #return Integer the levenshtein distance (0 and above).
*/
get: function(str1, str2) {
// base cases
if (str1 === str2) return 0;
if (str1.length === 0) return str2.length;
if (str2.length === 0) return str1.length;
// two rows
var prevRow = new Array(str2.length + 1),
curCol, nextCol, i, j, tmp;
// initialise previous row
for (i=0; i<prevRow.length; ++i) {
prevRow[i] = i;
}
// calculate current row distance from previous row
for (i=0; i<str1.length; ++i) {
nextCol = i + 1;
for (j=0; j<str2.length; ++j) {
curCol = nextCol;
// substution
nextCol = prevRow[j] + ( (str1.charAt(i) === str2.charAt(j)) ? 0 : 1 );
// insertion
tmp = curCol + 1;
if (nextCol > tmp) {
nextCol = tmp;
}
// deletion
tmp = prevRow[j + 1] + 1;
if (nextCol > tmp) {
nextCol = tmp;
}
// copy current col value into previous (in preparation for next iteration)
prevRow[j] = curCol;
}
// copy last col value into previous (in preparation for next iteration)
prevRow[j] = nextCol;
}
return nextCol;
}
};
var the_string1;
try {
the_string1 = decodeURI(string1).toLowerCase();
} catch (ex) {
the_string1 = string1.toLowerCase();
}
try {
the_string2 = decodeURI(string2).toLowerCase();
} catch (ex) {
the_string2 = string2.toLowerCase();
}
return Levenshtein.get(the_string1, the_string2)
""";
WITH strings AS (
SELECT '1: 6c71d997ba39' string1, '2: 6c71d997d269' string2
)
SELECT string1, string2, EDIT_DISTANCE(string1, string2) changes
FROM strings
with result
Row string1 string2 changes
1 1: 6c71d997ba39 2: 6c71d997d269 4
SELECT
(SELECT COUNTIF(c != s2[OFFSET(off)])
FROM UNNEST(SPLIT(s1, '')) AS c WITH OFFSET off) AS count
FROM dataset.table
Source: https://stackoverflow.com/a/57499387/11059644
Ready to use shared UDFs - Levenshtein distance:
SELECT fhoffa.x.levenshtein('felipe', 'hoffa'), fhoffa.x.levenshtein('googgle', 'goggles'), fhoffa.x.levenshtein('is this the', 'Is This The')

For example, if coins = [1, 2, 5] and N = 11, return true if coins = [3, 77] and N = 100, return

wait online。~
Given a number of coins with different denominations, e.g. [1, 2, 5] and test if they could be used to make up a certain amount (N), assuming you can use unlimited number of coins in each denomination. For example, if coins = [1, 2, 5] and N = 11, return true if coins = [3, 77] and N = 100, return
The idea is use a recursive function (here it will calculate with one first coin vs array of other coins then recursively reduce size of coin array ).
But sr I'm not familiar with Objective-C so I write one using C#. Use should convert it to Objective-C.
bool CanDo(int n, int [] arr)
{
if (arr.Length == 1)
{
if (n % arr[0] == 0)
{
return true;
}
}
else
{
var ls = new List<int>(arr);
ls.RemoveAt(0);
int [] newarr = ls.ToArray(); //Create New array by deleting first element(current calculated element) of old array
for(int i = 0; i <= n/arr[0]; i++)
{
int next_n = n - i * arr[0];
if (next_n == 0)
{
return true;
}
else if (next_n < 0)
{
break;
}
else if(next_n > 0)
{
if( CanDo(next_n, newarr) )
{
return true;
}
}
}
}
return false;
}
This is full code in C# that can print to console first found solution.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static List<string> resultString = new List<string>();
static bool CanDo(int n, int [] arr)
{
if (arr.Length == 1)
{
if (n % arr[0] == 0)
{
resultString.Add(n/ arr[0] + "*" + arr[0]);
return true;
}
}
else
{
var ls = new List<int>(arr);
ls.RemoveAt(0);
int [] newarr = ls.ToArray(); //Create New array by deleting first element of old array
for(int i = 0; i <= n/arr[0]; i++)
{
if (resultString.Count > 0)
{
resultString.RemoveAt(resultString.Count - 1);
}
int next_n = n - i * arr[0];
if (next_n == 0)
{
resultString.Add(i + "*" + arr[0]);
return true;
}
else if (next_n < 0)
{
break;
}
else if(next_n > 0)
{
if (i != 0)
{
resultString.Add(i + "*" + arr[0] + " + ");
}
if( CanDo(next_n, newarr) )
{
return true;
}
}
}
}
return false;
}
static void Main(string[] args)
{
try
{
int[] arr = { 3, 5, 7 };
int N = 20;
resultString = new List<string>();
if (CanDo(N, arr))
{
resultString.ForEach(Console.WriteLine);
Console.Read();
}
else
{
Console.Write("Can't do");
Console.Read();
}
}
catch (Exception ex)
{
//handle exception
}
}
}
}

Time/Space-Complexity method

I got a question to answer with the best complexity we can think about.
We got one sorted array (int) and X value. All we need to do is to find how many places in the array equals the X value.
This is my solution to this situation, as i don't know much about complexity.
All i know is that better methods are without for loops :X
class Question
{
public static int mount (int [] a, int x)
{
int first=0, last=a.length-1, count=0, pointer=0;
boolean found=false, finish=false;
if (x < a[0] || x > a[a.length-1])
return 0;
while (! found) **//Searching any place in the array that equals to x value;**
{
if ( a[(first+last)/2] > x)
last = (first+last)/2;
else if ( a[(first+last)/2] < x)
first = (first+last)/2;
else
{
pointer = (first+last)/2;
count = 1;
found = true; break;
}
if (Math.abs(last-first) == 1)
{
if (a[first] == x)
{
pointer = first;
count = 1;
found = true;
}
else if (a[last] == x)
{
pointer = last;
count = 1;
found = true;
}
else
return 0;
}
if (first == last)
{
if (a[first] == x)
{
pointer = first;
count = 1;
found = true;
}
else
return 0;
}
}
int backPointer=pointer, forwardPointer=pointer;
boolean stop1=false, stop2= false;
while (!finish) **//Counting the number of places the X value is near our pointer.**
{
if (backPointer-1 >= 0)
if (a[backPointer-1] == x)
{
count++;
backPointer--;
}
else
stop1 = true;
if (forwardPointer+1 <= a.length-1)
if (a[forwardPointer+1] == x)
{
count++;
forwardPointer++;
}
else
stop2 = true;
if (stop1 && stop2)
finish=true;
}
return count;
}
public static void main (String [] args)
{
int [] a = {-25,0,5,11,11,99};
System.out.println(mount(a, 11));
}
}
The print command count it right and prints "2".
I just want to know if anyone can think about better complexity for this method.
Moreover, how can i know what is the time/space-complexity of the method?
All i know about time/space-complexity is that for loop is O(n). I don't know how to calculate my method complexity.
Thank a lot!
Editing:
This is the second while loop after changing:
while (!stop1 || !stop2) //Counting the number of places the X value is near our pointer.
{
if (!stop1)
{
if ( a[last] == x )
{
stop1 = true;
count += (last-pointer);
}
else if ( a[(last+forwardPointer)/2] == x )
{
if (last-forwardPointer == 1)
{
stop1 = true;
count += (forwardPointer-pointer);
}
else
forwardPointer = (last + forwardPointer) / 2;
}
else
last = ((last + forwardPointer) / 2) - 1;
}
if (!stop2)
{
if (a[first] == x)
{
stop2 = true;
count += (pointer - first);
}
else if ( a[(first+backPointer)/2] == x )
{
if (backPointer - first == 1)
{
stop2 = true;
count += (pointer-backPointer);
}
else
backPointer = (first + backPointer) / 2;
}
else
first = ((first + backPointer) / 2) + 1;
}
}
What do you think about the changing? I think it would change the time complexity to O(long(n)).
First let's examine your code:
The code could be heavily refactored and cleaned (which would also result in more efficient implementation, yet without improving time or space complexity), but the algorithm itself is pretty good.
What it does is use standard binary search to find an item with the required value, then scans to the back and to the front to find all other occurrences of the value.
In terms of time complexity, the algorithm is O(N). The worst case is when the entire array is the same value and you end up iterating all of it in the 2nd phase (the binary search will only take 1 iteration). Space complexity is O(1). The memory usage (space) is unaffected by growth in input size.
You could improve the worst case time complexity if you keep using binary search on the 2 sub-arrays (back & front) and increase the "match range" logarithmically this way. The time complexity will become O(log(N)). Space complexity will remain O(1) for the same reason as before.
However, the average complexity for a real-world scenario (where the array contains various values) would be very close and might even lean towards your own version.