Largest possible palindromic substring of a given string in JavaScript - algorithm

This is an interview question which I was asked to write. The time complexity should be small. I couldn't write a proper solution for this problem.
Question : Largest possible palindromic substring of a given string in JavaScript

Kindly go through the following code:
var longestPalindrome = function(string) {
var length = string.length;
var result = "";
var centeredPalindrome = function(left, right) {
while (left >= 0 && right < length && string[left] === string[right]) {
//expand in each direction.
left--;
right++;
}
return string.slice(left + 1, right);
};
for (var i = 0; i < length - 1; i++) {
var oddPal = centeredPalindrome(i, i + 1);
var evenPal = centeredPalindrome(i, i);
if (oddPal.length > 1)
console.log("oddPal: " + oddPal);
if (evenPal.length > 1)
console.log("evenPal: " + evenPal);
if (oddPal.length > result.length)
result = oddPal;
if (evenPal.length > result.length)
result = evenPal;
}
return "the palindrome is: " + result + " and its length is: " + result.length;
};
console.log(
longestPalindrome("nan noon is redder")
);
Credits: #Paul Roub

Related

Confusion related to the time complexity of this algorithm

I was going through some of the articles of the leetcode. Here is one of them https://leetcode.com/articles/optimal-division/.
Given a list of positive integers, the adjacent integers will perform the float division. For example, [2,3,4] -> 2 / 3 / 4.
However, you can add any number of parenthesis at any position to change the priority of operations. You should find out how to add parenthesis to get the maximum result, and return the corresponding expression in string format. Your expression should NOT contain redundant parenthesis.
Example:
Input: [1000,100,10,2]
Output: "1000/(100/10/2)"
Explanation:
1000/(100/10/2) = 1000/((100/10)/2) = 200
However, the bold parenthesis in "1000/((100/10)/2)" are redundant,
since they don't influence the operation priority. So you should return "1000/(100/10/2)".
Other cases:
1000/(100/10)/2 = 50
1000/(100/(10/2)) = 50
1000/100/10/2 = 0.5
1000/100/(10/2) = 2
I think the time complexity of the solution is O(N^2) isn't it?
Here is the memoization solution
public class Solution {
class T {
float max_val, min_val;
String min_str, max_str;
}
public String optimalDivision(int[] nums) {
T[][] memo = new T[nums.length][nums.length];
T t = optimal(nums, 0, nums.length - 1, "", memo);
return t.max_str;
}
public T optimal(int[] nums, int start, int end, String res, T[][] memo) {
if (memo[start][end] != null)
return memo[start][end];
T t = new T();
if (start == end) {
t.max_val = nums[start];
t.min_val = nums[start];
t.min_str = "" + nums[start];
t.max_str = "" + nums[start];
memo[start][end] = t;
return t;
}
t.min_val = Float.MAX_VALUE;
t.max_val = Float.MIN_VALUE;
t.min_str = t.max_str = "";
for (int i = start; i < end; i++) {
T left = optimal(nums, start, i, "", memo);
T right = optimal(nums, i + 1, end, "", memo);
if (t.min_val > left.min_val / right.max_val) {
t.min_val = left.min_val / right.max_val;
t.min_str = left.min_str + "/" + (i + 1 != end ? "(" : "") + right.max_str + (i + 1 != end ? ")" : "");
}
if (t.max_val < left.max_val / right.min_val) {
t.max_val = left.max_val / right.min_val;
t.max_str = left.max_str + "/" + (i + 1 != end ? "(" : "") + right.min_str + (i + 1 != end ? ")" : "");
}
}
memo[start][end] = t;
return t;
}
}

Algorithm to convert string from one format to other

I was looking at a problem which stated to convert strings as below.
s = "3[a]2[bc]", return "aaabcbc".
s = "3[a2[c]]", return "accaccacc".
s = "2[abc]3[cd]ef", return "abcabccdcdcdef".
I was able to understand how to do that.
I was thinking is there a way to do this in reverse. when given a string like abcabccdcdcdef I understand there can be many possibilities of representation. I was looking can we do it in representation which takes lowest memory(Not algorithmic but of the final string).
for max efficiency, we'd want to have as much reduction as possible. I think I would do something like this (it may not be the most efficient algorithm):
s = "whateverwhateveryouwantwantwantababababababababc"
possibilities = []
repeats = []
def findRepeats(repeats, s, length):
for i in range(0, len(s) - 2 * length + 1):
if s[i:i+length] == s[i+length:i+2*length]:
trackInd = i+length
times = 2
while trackInd+2*length <= len(s):
if (s[trackInd:trackInd+length]==s[trackInd+length:trackInd+2*length]):
times += 1
else: break
trackInd += length
repeats.append((i, times, s[i:i+length]))
return repeats
for i in range(0, len(s)):
repeats = findRepeats(repeats, s, i)
def formPossibility(repeats, s):
build = ""
i = 0
while i < len(s):
pass = True
for repeat in repeats:
if repeat[0] == i:
pass = False
build += repeat[1] + "["
build += repeat[2] + "]"
break
if pass:
build += s[i]
# I didn't finish this but you would loop through all the repeats and test
# them to see if they overlap, and then you would take all the posibilities
# of different ways to make them so that some are there, and some are not.
# in any case, I think that you get the idea.
# I couldn't finish this because I am doing the coding on stackoverflow and
# its like so painful and so hard to debug. also I don't have enough time sorry
Don't know if it is the most efficient or if it is efficient at all, but here is my approach using js.
function format(pattern, length, times) {
var result = "";
if (times == 0) {
result = pattern;
} else {
result = (times + 1).toString() + "[" + pattern + "]";
}
return result;
}
function encode(input) {
var result = "";
var pattern = { length: 1, times: 0 };
var i = 1;
while (i <= input.length / 2) {
var subpattern = input.substr(0, i);
var j = 0;
while (input.substr(i + j * i, i) == subpattern && j + i < input.length) {
j++;
}
if (i * j > pattern.length * pattern.times) {
pattern.length = i;
pattern.times = j;
}
i++;
}
if (pattern.length > 1) {
result = format(encode(input.substr(0, pattern.length)), pattern.length, pattern.times);
} else {
result = format(input.substr(0, pattern.length), pattern.length, pattern.times);
}
if (pattern.length + pattern.length * pattern.times < input.length) {
result += encode(input.substr(pattern.length + pattern.length * pattern.times, input.length));
}
return result;
}

For a given string which contains only digits , what's the optimal approach to return all valid ip address combinations?

Example:
Given “25525511135”
Output : [“255.255.11.135”, “255.255.111.35”]. (sorted order)
Kindly let me know if we could do a depth first search over here ?(that's the only thing striking me )
Why is it important to have an 'optimal' approach for answering this?
There are not many permutations so the simple approach of checking every combination that fits into the IP format and then filtering out those that have out of range numbers will easily work.
It's unlikely to be a bottle neck for whatever this is part of.
You probably want a dynamic programming algorithm for the general case (something like
http://www.geeksforgeeks.org/dynamic-programming-set-32-word-break-problem/).
Instead of testing whether prefixes can be segmented into words in the dictionary, you'd be testing to see whether the prefixes are prefixes of some valid IPv4 address.
Brutal DFS is acceptable in this problem:
class Solution{
private:
vector<string> ans;
int len;
string cur, rec, str;
bool IsOk(string s) {
if(s[0] == '0' && s.size() > 1) return false;
int sum = 0;
for(int i = 0; i < s.size(); i ++) {
if(s[i] == '.') return false;
sum = sum * 10 + s[i] - '0';
}
if(sum >= 0 && sum <= 255) return true;
return false;
}
void dfs(int x, int cnt) {
if(x == len) {
if(str.size() != len + 4) return ;
string tmp(str);
tmp.erase(tmp.size() - 1, 1);
if(cnt == 4) ans.push_back(tmp);
return ;
}
if(cnt > 4 || str.size() > len + 4) return ;
string tmp = cur;
cur += rec[x];
if(!IsOk(cur)) {
cur = tmp;
return ;
}
dfs(x + 1, cnt);
string tmp2 = cur + '.';
str += tmp2;
cur = "";
dfs(x + 1, cnt + 1);
str.erase(str.size() - tmp2.size(), tmp2.size());
cur = tmp;
}
public:
vector<string> restoreIpAddresses(string s) {
this->len = s.size();
this->rec = s;
cur = str = "";
ans.clear();
dfs(0, 0);
return ans;
}
};
Here is a recursive solution on JavaScript. The result is not sorted.
// Task from https://www.geeksforgeeks.org/program-generate-possible-valid-ip-addresses-given-string/
// Given a string containing only digits, restore it by returning all possible valid IP address combinations.
//
// Example:
// Input : 25525511135
// Output : [“255.255.11.135”, “255.255.111.35”]
//
(function () {
function getValidIP(str) {
const result = [];
const length = str.length;
check(0, 0, '');
function check(start, level, previous){
let i = 0;
let num;
if (level === 3) {
num = str.substring(start);
if (num && num < 256) {
result.push(`${previous}.${num}`);
}
return;
}
num = str.substring(start, start + 1);
if (num == 0) {
check(start + 1, level + 1, level === 0 ? `${num}`: `${previous}.${num}`);
} else {
while (num.length < 4 && num < 256 && start + i + 1 < length) {
check(start + i + 1, level + 1, level === 0 ? `${num}`: `${previous}.${num}`);
i++;
num = str.substring(start, start + i + 1);
}
}
}
return result;
}
console.log('12345:')
console.time('1-1');
console.log(getValidIP('12345'));
console.timeEnd('1-1');
console.log('1234:')
console.time('1-2');
console.log(getValidIP('1234'));
console.timeEnd('1-2');
console.log('2555011135:')
console.time('1-3');
console.log(getValidIP('2555011135'));
console.timeEnd('1-3');
console.log('222011135:')
console.time('1-4');
console.log(getValidIP('222011135'));
console.timeEnd('1-4');
})();

How to find the answer to a XOR hash if I have the key & one number

I have a little routine that makes up a cumulative XOR hash. It's as if it is a savings account which gets bigger, cumulatively daily.. but in this sense we're saying the answer is being generated cumulatively and the key is always present.
I have taken a string of chars
pseudo code:
char H[10] = { "ABCDEFGHI", "\0" };
and I used 9 32-bit numeric keys to hash them in XOR encryption.
I did it like this:
for (i;i<10;i++)
bitset<32> K ^= H[i] ^ NUMKEY[i];
Now this makes it impervious without the calculus plotting I did (see what I did there?) So K is an accumulation of calculus points, which are completely predictable according to calculus.
as far as I know, to undo it, I do
for (i;i<10;i++) {
X=0;
X ^= K ^ NUMKEY[i];
}
Is there other math involved? I think I have to take that X and do a little K - X to find the true derivative.
Here's the current routine I have for it. But I'm not getting what I'm looking for.
for_each (std::istreambuf_iterator<char>(in), \
std::istreambuf_iterator<char>(), \
[&] (long x) {
t=s_nop(t,0);
cred.push_back(t);
alpha = static_cast<long>(cred[size]);
delta = static_cast<long>(x);
lambda ^= (alpha ^ delta);
size++;
});
for (;i<bn;i++) {
alpha = static_cast<unsigned long>(cred[bn-1-i]);
int m = lambda.to_ulong(), n = alpha.to_ulong();
long hash1 = abs((m-n-1)%256-1);
delta = static_cast<unsigned long>(hash1);
btrace.push_back(hash1);
cout << hash1 << " ";
}
Please have a safe and Merry Christmas. Thank you in advance!
I think what you might really want is a one time pad. (the snippet is javascript as pseudocode moving in that direction)
//ignore these top 3 functions (they're just for printing output)
function appendLine(text, target, space, color) {
var line = document.createElement("div");
line.style.border = "1px solid " + color;
line.style.padding = line.style.margin = space;
line.style["font-family"] = "monospace";
line.appendChild(document.createTextNode(text));
target.appendChild(line);
return line;
}
function makeSection(title) {
var d = appendLine(title, document.body, "5px", "#dddddd");
var results = document.createElement("div");
d.appendChild(results);
return function(result) {
appendLine(result, results, "2px", "#eeeeee");
};
}
function toHex(arr) {
return arr.map(function(n){
var h = (n >>> 0).toString(16).toUpperCase();
while(h.length < 8) h = "0" + h;
return h;
}).join(",");
}
//your message
var H = "ABCDEFGHI".split("").map(function(c){return c.charCodeAt(0)});
//your secret encoding key
var NUMKEY = Array.apply(null, Array(9)).map(function(){return Math.random() * Math.pow(2, 32)});
//what you're doing
(function() {
var section = makeSection("what you're doing:");
section("ABCDEFGHI as array of 32bit numbers: " + toHex(H));
section("NUMKEY: " + toHex(NUMKEY));
var K = 0;
for (var i = 0; i < 10; i++) {
K ^= H[i] ^ NUMKEY[i];
}
section("K: " + toHex([K]));
var X = 0;
for (var i = 0; i < 10; i++) {
X ^= K ^ NUMKEY[i];
}
section("X: " + toHex([X]));
})();
//what you're trying to do
(function() {
var section = makeSection("what you're trying to do:");
section("ABCDEFGHI as array of 32bit numbers: " + toHex(H));
section("NUMKEY: " + toHex(NUMKEY));
var Hs_XORd = 0;
for (var i = 0; i < 10; i++) {
Hs_XORd ^= H[i];
}
section("H's XOR'd together: " + toHex([Hs_XORd]));
var NUMKEYs_XORd = 0;
for (var i = 0; i < H.length; i++) {
NUMKEYs_XORd ^= NUMKEY[i];
}
section("NUMKEY's XOR'd together: " + toHex([NUMKEYs_XORd]));
var K = NUMKEYs_XORd ^ Hs_XORd;
section("K: " + toHex([K]));
var X = K ^ NUMKEYs_XORd;
section("X (should be the same as H's XOR'd together): " + toHex([X]));
})();
//what I think you mean to be doing (one time pad)
(function() {
var section = makeSection("what I think you mean to be doing (one time pad):");
section("ABCDEFGHI as array of 32bit numbers: " + toHex(H));
section("NUMKEY: " + toHex(NUMKEY));
var K = [];
for (var i = 0; i < H.length; i++) {
K[i] = H[i] ^ NUMKEY[i];
}
section("K (encoded message using NUMKEY as one time pad): " + toHex(K));
var X = [];
for (var i = 0; i < K.length; i++) {
X[i] = K[i] ^ NUMKEY[i];
}
section("X (decoded message, should be the same as ABCDEFGHI): " + toHex(X));
})();

Minimize the sequence by putting appropriate operations ' DP'

Given a sequence,say,
222
We have to put a '+' or '* ' between each adjacent pair.
'* ' has higher precedence over '+'
We have to o/p the string whose evaluation leads to minimum value.
O/p must be lexicographically smallest if there are more than one.
inp:222
o/p: 2*2+2
Explaination:
2+2+2=6
2+2*2=6
2*2+2=6
of this 3rd is lexicographically smallest.
I was wondering how to construct a DP solution for this.
Let DP[N] be the smallest value we can obtain using the first N elements. I will do a recursive implementation(using memoization) with pseudocode:
int solve(int index)
{
if (index == N)
return 0;
if (DP[index] already computed)
return DP[index];
int result = INFINITELY LARGE NUMBER;
//put a + sign
result = min(result, input[index] + solve(index + 1));
//put consecutive * signs
int cur = input[index];
for (int i = index + 1; i < N; i++)
{
cur *= input[i];
result = min(result, cur + solve(i + 1));
}
return DP[index] = result;
}
Call it with solve(0);
You can easily reconstruct the solution after this. I haven't tested it and maybe I have missed an edge case in the pseudocode but it should give you the right track.
string reconstruct(int index)
{
if (index == N)
return "";
string result = "";
//put consecutive * signs
int cur = input[index];
string temp = ToString(input[index]);
for (int i = index + 1; i < N; i++)
{
cur *= input[i];
temp += "*";
if (DP[index] == cur + DP[i + 1])
result = temp + reconstruct(i + 1);
}
//put a + sign
if (result == "")
result = ToString(input[index]) + "+" + reconstruct(index + 1);
return result;
}
string result = reconstruct(0);
P.S Sorry for the many edits.

Resources