How to find the longest palindromic subsequence (not its length) - algorithm

I want to find out the longest palindromic subsequence in a string. Everywhere I find the algorithm to find out the length of the subsequence, with the statement that the algo can be extended to return the subsequence as well, but nowhere have I found how. Can anybody explain how can I get the sequence as well?

Since you mentioned the link Longest Palindromic Subsequence in geeksforgeeks, I modified the solution to output the result. I think we need one auxiliary two-dimensions array to stored how the palindromic subsequence comes from, so we can get the result through the auxiliary array at last. You can see the logic in the below code:
#include<iostream>
#include<cstring>
using namespace std;
// A utility function to get max of two integers
int max (int x, int y) { return (x > y)? x : y; }
// Returns the length of the longest palindromic subsequence in seq
int lps(char *str,char *result)
{
int n = strlen(str);
int i, j, cl;
int L[n][n]; // Create a table to store results of subproblems
int Way[n][n];// Store how the palindrome come from.
// Strings of length 1 are palindrome of lentgh 1
for (i = 0; i < n; i++)
{
L[i][i] = 1;
Way[i][i]=0;
}
// Build the table. Note that the lower diagonal values of table are
// useless and not filled in the process. The values are filled in a
// manner similar to Matrix Chain Multiplication DP solution (See
// http://www.geeksforgeeks.org/archives/15553). cl is length of
// substring
for (cl=2; cl<=n; cl++)
{
for (i=0; i<n-cl+1; i++)
{
j = i+cl-1;
if (str[i] == str[j] && cl == 2)
{
L[i][j] = 2;
Way[i][j]=0;
}
else if (str[i] == str[j])
{
L[i][j] = L[i+1][j-1] + 2;
Way[i][j]=0;
}
else
{
if(L[i][j-1]>L[i+1][j])
{
L[i][j]=L[i][j-1];
Way[i][j]=1;
}
else
{
L[i][j]=L[i+1][j];
Way[i][j]=2;
}
}
}
}
int index=0;
int s=0,e=n-1;
while(s<=e)
{
if(Way[s][e]==0)
{
result[index++]=str[s];
s+=1;
e-=1;
}
else if(Way[s][e]==1)e-=1;
else if(Way[s][e]==2)s+=1;
}
int endIndex=(L[0][n-1]%2)?index-1:index;
for(int k=0;k<endIndex;++k)result[L[0][n-1]-1-k]=result[k];
result[index+endIndex]='\0';
return L[0][n-1];
}
/* Driver program to test above functions */
int main()
{
char seq[] = "GEEKSFORGEEKS";
char result[20];
cout<<"The lnegth of the LPS is "<<lps(seq,result)<<":"<<endl;
cout<<result<<endl;
getchar();
return 0;
}
Hope it helps!
Below is the explanation:
Let X[0..n-1] be the input sequence of length n and L(0, n-1) be the length of the longest palindromic sub-sequence of X[0..n-1].
There are 5 cases in total.
1)Every single character is a palindrome of length 1.
L(i, i) = 1 for all indexes i in given sequence.
2)There are only 2 characters and both are same.
L(i, j) = 2.
3)There are more than two characters, and first and last characters are the same
L(i, j) = L(i + 1, j - 1) + 2
4)First and last characters are not the same and L(i + 1, j)< L(i, j - 1). L(i, j) = L(i, j - 1).
5)First and last characters are not the same and L(i + 1, j)>=L(i, j - 1). L(i, j) = L(i + 1, j).
We can observed that only in case 1,2 and 3, the character X[i] is included in the final result. We used a two-dimension auxiliary array to represent how the palindromic sub-sequence comes from.
value 0 for case 1,2,3; value 1 for case 4; value 2 for case 5.
With the auxiliary array Way. We can get the result as below:
Let two variables s=0 and e=n-1.
While s<=e
Loop
If Way[s][e]==0 Then X[s] should be included in the result and we store it in our result array.
Else if Way[s][e]==1 Then X[s] should not be include in the result and update e=e-1 (because our result comes from case 4).
Else if Way[s][e]==2 Then X[s] should not be include in the result and update s=s+1 (because our result comes from case 5).
The loop should be terminated when s>e. In that way we can get half part of the result and we can easily extend it to get the whole result.

Keep a backpointer as well as a value in your dynamic programming table for each cell. Then follow the traceback from the end of the table to reconstruct the subsequence.

The trick works like this:
save the reverse of your string in a temporary buffer
use the Longest Common Substring Algorithm to find the LCS.
Note that by definition of your second string, the LCS of both strings is the longest palindrome as well.

The below solution is pretty straight forward and requires no additional use of any other matrix.
Here we are just tracing back our path to generate the longest palindromic sub sequence.
int lps(char *str)
{
int n = strlen(str);
int i, j, cl;
int L[n][n];
for (i = 0; i < n; i++)
L[i][i] = 1;
for (cl=2; cl<=n; cl++)
{
for (i=0; i<n-cl+1; i++)
{
j = i+cl-1;
if (str[i] == str[j] && cl == 2)
L[i][j] = 2;
else if (str[i] == str[j])
L[i][j] = L[i+1][j-1] + 2;
else
L[i][j] = max(L[i][j-1], L[i+1][j]);
}
}
cout<<L[0][n-1]<<endl;
i = 0,j = n-1;
vector<char> result;
while(i<=j)
{
if(str[i]==str[j])
{
result.push_back(str[i]);
i++,j--;
}
else if(L[i][j-1]>L[i+1][j])
{
j--;
}
else
{
i++;
}
}
if(L[0][n-1]%2==0)
{
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
reverse(result.begin(),result.end());
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
}
else
{
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
reverse(result.begin(),result.end());
result.erase(result.begin());
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
}
}

A Java approach .Building the string from the LPS matrix generated during calculation of length of the palindromic sub-sequence.
private static void LongestPalindromicSubsequence(char a[])
{
int len=a.length;
int lps[][]=new int[len][len];
int l=1;
for(int i=0;i<len;i++)
{
lps[i][i]=1; //---------> Length of subsequence of string of length=1 is 1 <------------
}
for(int subsLen=2;subsLen<=len;subsLen++)
{
for( int i=0;i<(len-subsLen+1);i++)
{
int j=i+subsLen-1;
if(a[i]==a[j]&&subsLen==2)
{
lps[i][j]=2;
}
else
{
if(a[i]!=a[j])
{
lps[i][j]=Math.max(lps[i+1][j],lps[i][j-1]);
}
else
{
lps[i][j]=2+lps[i+1][j-1];
}
}
}
}
// System.out.println("Length of longest Palindromic subsequence: "+lps[0][len-1]);
printLongestPalindromicsubsequence(a,lps);
}
private static void printLongestPalindromicsubsequence(char[] a, int[][] lps)
{
int len=a.length;
int end=lps[0][len-1];
char str[]=new char[end+1];
str[end--]='\0';
int i=0,j=len-1;
while(end>=0&&i<=j)
{
if(a[i]==a[j])
{
str[end--]=a[i];
i++;
j--;
}
else
{
if(lps[i+1][j]>lps[i][j-1])
{
i++;
}
else
{
j--;
}
}
}
if(lps[0][len-1]%2!=0)
{
i=0;
int mid=lps[0][len-1]/2;
j=str.length-2;
while(j>mid)
{
str[i++]=str[j--];
}
}
else
{
i=0;
int mid=lps[0][len-1]/2;
j=str.length-2;
while(j>=mid)
{
str[i++]=str[j--];
}
}
for(i=0;i<str.length;i++)
System.out.print(str[i]);
}

A sample java implementation. Feel free to be brutal with your review comments.
public class LongestPalindrome {
public static void main(String... arguments) {
final String content = "GOBANANAS";
String palindrome = getLongestPalindrome(content);
System.out.println(palindrome);
}
private static String getLongestPalindrome(final String content) {
String lastPalindrome = "";
for (int lastIndex = content.length(); lastIndex >= 0; lastIndex--) {
for (int i = 0; i <= lastIndex; i++) {
String part = content.substring(i, lastIndex);
if (part.length() > lastPalindrome.length() && part.length() > 1) {
boolean isPalindrome = isPalindrome(part);
if (isPalindrome) {
lastPalindrome = part;
System.out.println(String.format("%s : %s", part, isPalindrome));
}
}
}
}
return lastPalindrome;
}
private static boolean isPalindrome(String string) {
String reverse = (new StringBuilder(string)).reverse().toString();
return (string.equals(reverse));
}
}

Related

How to print the Longest Palindromic Subsequence? If there are multiple LPS we need to print the one which starts at lowest index

Here is my code, it prints the LPS correctly but can't print the one which starts from the lowest index if multiple LPS exist. I tried handling a case seperately when dp[i][j-1]==dp[i-1][j] but for some reason that dosen't work also. Any help would really be appreciated.
public class Solution {
public static String longestPalinSubstring(String str) {
String rev = reverse(str);
int n = str.length();
int[][] dp = new int[n+1][n+1];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(str.charAt(i-1)==rev.charAt(j-1)){
dp[i][j] = 1 + dp[i-1][j-1];
}else{
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
int i=n, j=n;
String ans="";
while(i>0 && j>0){
if(str.charAt(i-1)==rev.charAt(j-1)){
ans+=str.charAt(i-1);
--i;
--j;
}else{
if(dp[i-1][j]<dp[i][j-1]){
j--;
}else{
i--;
}
}
}
return reverse(ans);
}
public static String reverse(String s){
String ans = "";
for(int i=s.length()-1;i>=0;i--){
ans += s.charAt(i);
}
return ans;
}
}
I am providing an alternative yet easy dynamic programming implementation which will solve your problem.
dp[i][j] = 1 represents palindrome of size i ending at position j in the given string.
Example: str = "aprabaprrbcb" then dp[3][5] represents "aba". Since "aba" is palindrome, dp[3][5] = 1.
We just need to check if first and last character of the current sub-string is equal. If equal then check if inner sub-string (string after removing first and last character of current string) is palindrome or not. Since the inner sub-string size will be i-2 and ends at j-1, hence we check dp[i-2][j-1].
Now maintain 2 variables lar_size and lar_pos for size of longest palindrome and last index of that palindrome.
import java.util.Scanner;
public class LPS {
public static void main(String[] args){
Scanner sc= new Scanner(System.in);
String str = sc.nextLine();
sc.close();
int n= str.length();
int[][] dp = new int[n+1][n+1];
int lar_size=-1;
int lar_pos= -1;
for(int i=0;i<=n;i++){
dp[0][i]=1; //string of length 0 ending at position i is a palindrome
dp[1][i]=1; //string of length 1 ending at position i is a palindrome
}
//
for( int i=2;i<=n;i++){
for( int j=i; j<=n;j++){
if(str.charAt(j-1) == str.charAt(j-i)){
if(dp[i-2][j-1] == 1){
dp[i][j]=1;
if(lar_size < i){ // for lowest index palindrome
lar_size=i;
lar_pos=j;
}
}
}
}
}
System.out.println(lar_size+" "+(lar_pos-lar_size+1));
String ans="";
for(int i=0;i<lar_size;i++){
ans+=str.charAt(lar_pos-lar_size+1 +i);
}
System.out.println(ans);
}
}

Missing integer variation - O(n) solution needed [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
The problem comes from Codility programming training and it sounds as follows:
we have an array (A[]) with n (ranging from 1 to 100,000) elements and these are our parameters. The elements of the array are integers from −2,147,483,648 to 2,147,483,647, and we need to find smallest positive integer that is NOT in the array. Of course this could be done easily in O(n*log n) by sorting them all and going through the sorted array, looking for the missing posiitve number (this last operation has O(n) worst time complexity in my solution). But according to Codility, this ENTIRE problem can be done in O(n), and I cannot see any way to do that. Could someone give some tips to let me get un-stuck?
PS Here is a link to detailed description of the problem which I'm not allowed to copy - https://codility.com/c/intro/demo35UEXH-EAT
By pigeonhole principle, at least one of the numbers 1, 2, ..., n+1 is not in the array.
Let us create a boolean array b of size n+1 to store whether each of these numbers is present.
Now, we process the input array. If we find a number from 1 to n+1, we mark the corresponding entry in b. If the number we see does not fit into these bounds, just discard it and proceed to the next one. Both cases are O(1) per input entry, total O(n).
After we are done processing the input, we can find the first non-marked entry in our boolean array b trivially in O(n).
Simple solution 100% in Java.
Please note it is O(nlogn) solution but gives 100% result in codility.
public static int solution(final int[] A)
{
Arrays.sort(A);
int min = 1;
// Starting from 1 (min), compare all elements, if it does not match
// that would the missing number.
for (int i : A) {
if (i == min) {
min++;
}
}
return min;
}
wrote this today and got 100/100. not the most elegant solution, but easy to understand -
public int solution(int[] A) {
int max = A.length;
int threshold = 1;
boolean[] bitmap = new boolean[max + 1];
//populate bitmap and also find highest positive int in input list.
for (int i = 0; i < A.length; i++) {
if (A[i] > 0 && A[i] <= max) {
bitmap[A[i]] = true;
}
if (A[i] > threshold) {
threshold = A[i];
}
}
//find the first positive number in bitmap that is false.
for (int i = 1; i < bitmap.length; i++) {
if (!bitmap[i]) {
return i;
}
}
//this is to handle the case when input array is not missing any element.
return (threshold+1);
}
public int solutionMissingInteger(int[] A) {
int solution = 1;
HashSet<Integer> hashSet = new HashSet<>();
for(int i=0; i<A.length; ++i){
if(A[i]<1) continue;
if(hashSet.add(A[i])){
//this int was not handled before
while(hashSet.contains(solution)){
solution++;
}
}
}
return solution;
}
Simple Java soution. Scored 100/100 in correctness and performance.
public int solution(int[] A) {
int smallestMissingInteger = 1;
if (A.length == 0) {
return smallestMissingInteger;
}
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < A.length; i++) {
if (A[i] > 0) {
set.add(A[i]);
}
}
while (set.contains(smallestMissingInteger)) {
smallestMissingInteger++;
}
return smallestMissingInteger;
}
Build a hash table of all the values. For the numbers 1 to n + 1, check if they are in the hash table. At least one of them is not. Print out the lowest such number.
This is O(n) expected time (you can get with high probability). See #Gassa's answer for how to avoid the hash table in favor of a lookup table of size O(n).
JavaScript 100%
function solution(A) {
let sortedOb = {};
let biggest = 0;
A.forEach(el => {
if (el > 0) {
sortedOb[el] = 0;
biggest = el > biggest ? el : biggest;
}
});
let arr = Object.keys(sortedOb).map(el => +el);
if (arr.length == 0) return 1;
for(let i = 1; i <= biggest; i++) {
if (sortedOb[i] === undefined) return i;
}
return biggest + 1;
}
100% Javascript
function solution(A) {
// write your code in JavaScript (Node.js 4.0.0)
var max = 0;
var array = [];
for (var i = 0; i < A.length; i++) {
if (A[i] > 0) {
if (A[i] > max) {
max = A[i];
}
array[A[i]] = 0;
}
}
var min = max;
if (max < 1) {
return 1;
}
for (var j = 1; j < max; j++) {
if (typeof array[j] === 'undefined') {
return j
}
}
if (min === max) {
return max + 1;
}
}
C# scored 100%,
Explanation: use of lookup table where we store already seen values from input array, we only care about values that are greater than 0 and lower or equal than length on input array
public static int solution(int[] A)
{
var lookUpArray = new bool[A.Length];
for (int i = 0; i < A.Length; i++)
if (A[i] > 0 && A[i] <= A.Length)
lookUpArray[A[i] - 1] = true;
for (int i = 0; i < lookUpArray.Length; i++)
if (!lookUpArray[i])
return i + 1;
return A.Length + 1;
}
This is my solution is Swift 4
public func solution(_ A: inout [Int]) -> Int {
var minNum = 1
var hashSet = Set<Int>()
for int in A {
if int > 0 {
hashSet.insert(int)
}
}
while hashSet.contains(minNum) {
minNum += 1
}
return minNum
}
var array = [1,3,6]
solution(&array)
// Answer: 2
100%: the Python sort routine is not regarded as cheating...
def solution(A):
"""
Sort the array then loop till the value is higher than expected
"""
missing = 1
for elem in sorted(A):
if elem == missing:
missing += 1
if elem > missing:
break
return missing
It worked for me. It is not O(n), but little simpler:
import java.util.stream.*;
class Solution {
public int solution(int[] A) {
A = IntStream.of(A)
.filter(x->x>0)
.distinct()
.sorted()
.toArray();
int min = 1;
for(int val : A)
{
if(val==min)
min++;
else
return min;
}
return min;
}
}
My solution. 100%. In Java.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public int solution(int[] A) {
Arrays.sort(A);
ArrayList<Integer> positive = new ArrayList<>();
for (int i = 0; i < A.length; i++) {
if(A[i] > 0)
positive.add(A[i]);
}
if(positive.isEmpty()) return 1;
if(positive.get(0) > 1) return 1;
for(int i = 0; i < positive.size() - 1; i++) {
if(positive.get(i + 1) - positive.get(i) > 1)
return positive.get(i) + 1;
}
return positive.get(positive.size() - 1) + 1;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] A = {-5,1,2,3,4,6,7,8,9,5};
System.out.println(solution.solution(A));
}
}
javascript 100% 100%
first sort the array, you just need to scan positive elements so find index of 1 (if there is no 1 in array then answer is 1). then search elements after 1 till find missing number.
function solution(A) {
// write your code in JavaScript (Node.js 6.4.0)
var missing = 1;
// sort the array.
A.sort(function(a, b) { return a-b });
// try to find the 1 in sorted array if there is no 1 so answer is 1
if ( A.indexOf(1) == -1) { return 1; }
// just search positive numbers to find missing number
for ( var i = A.indexOf(1); i < A.length; i++) {
if ( A[i] != missing) {
missing++;
if ( A[i] != missing ) { return missing; }
}
}
// if cant find any missing number return next integer number
return missing + 1;
}
I believe the solution is more involved than 'marking' corresponding values using a boolean array of n (100,000) elements. The boolean array of size n will not 'directly' map to the possible range of values (−2,147,483,648 to 2,147,483,647).
This Java example I wrote attempts to map the 100K rows by mapping the value based on their offset from the max value. It also performs a modulus to reduce the resulting array to the same size as the sample element length.
/**
*
* This algorithm calculates the values from the min value and mods this offset with the size of the 100K sample size.
* This routine performs 3 scans.
* 1. Find the min/max
* 2. Record the offsets for the positive integers
* 3. Scan the offsets to find missing value.
*
* #author Paul Goddard
*
*/
public class SmallestPositiveIntMissing {
static int ARRAY_SIZE = 100000;
public static int solve(int[] array) {
int answer = -1;
Maxmin maxmin = getMaxmin(array);
int range = maxmin.max - maxmin.min;
System.out.println("min: " + maxmin.min);
System.out.println("max: " + maxmin.max);
System.out.println("range: " + range);
Integer[] values = new Integer[ARRAY_SIZE];
if (range == ARRAY_SIZE) {
System.out.println("No gaps");
return maxmin.max + 1;
}
for (int val: array) {
if (val > 0) {
int offset = val - maxmin.min;
int index = offset % ARRAY_SIZE;
values[index] = val;
}
}
for (int i = 0; i < ARRAY_SIZE; i++) {
if (values[i] == null) {
int missing = maxmin.min + i;
System.out.println("Missing: " + missing);
answer = missing;
break;
}
}
return answer;
}
public static Maxmin getMaxmin(int[] array) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int val:array) {
if (val >=0) {
if (val > max) max = val;
if (val < min) min = val;
}
}
return new Maxmin(max,min);
}
public static void main(String[] args) {
int[] A = arrayBuilder();
System.out.println("Min not in array: " + solve(A));
}
public static int[] arrayBuilder() {
int[] array = new int[ARRAY_SIZE];
Random random = new Random();
System.out.println("array: ");
for (int i=0;i < ARRAY_SIZE; i++) {
array[i] = random.nextInt();
System.out.print(array[i] + ", ");
}
System.out.println(" array done.");
return array;
}
}
class Maxmin {
int max;
int min;
Maxmin(int max, int min) {
this.max = max;
this.min = min;
}
}
Sweet Swift version. 100% correct
public func solution(inout A : [Int]) -> Int {
//Create a Hash table
var H = [Int:Bool]()
// Create the minimum possible return value
var high = 1
//Iterate
for i in 0..<A.count {
// Get the highest element
high = A[i] > high ? A[i] : high
// Fill hash table
if (A[i] > 0){
H[A[i]] = true
}
}
// iterate through possible values on the hash table
for j in 1...high {
// If you could not find it on the hash, return it
if H[j] != true {
return j
} else {
// If you went through all values on the hash
// and can't find it, return the next higher value
// e.g.: [1,2,3,4] returns 5
if (j == high) {
return high + 1
}
}
}
return high
}
int[] copy = new int[A.length];
for (int i : A)
{
if (i > 0 && i <= A.length)
{
copy[i - 1] = 1;
}
}
for (int i = 0; i < copy.length; i++)
{
if (copy[i] == 0)
{
return i + 1;
}
}
return A.length + 1;
Swift 3 - 100%
public func solution(_ A : inout [Int]) -> Int {
// write your code in Swift 3.0 (Linux)
var solution = 1
var hashSet = Set<Int>()
for int in A
{
if int > 0
{
hashSet.insert(int)
while hashSet.contains(solution)
{
solution += 1
}
}
}
return solution
}
Thanks to Marian's answer above.
This is my solution using python:
def solution(A):
m = max(A)
if m <= 0:
return 1
if m == 1:
return 2
# Build a sorted list with all elements in A
s = sorted(list(set(A)))
b = 0
# Iterate over the unique list trying to find integers not existing in A
for i in xrange(len(s)):
x = s[i]
# If the current element is lte 0, just skip it
if x <= 0:
continue;
b = b + 1
# If the current element is not equal to the current position,
# it means that the current position is missing from A
if x != b:
return b
return m + 1
Scored 100%/100% https://codility.com/demo/results/demoDCU7CA-SBR/
Create a binary array bin of N+1 length (C uses 0 based indexing)
Traverse the binary array O(n)
If A[i] is within the bounds of bin then mark bin entry at index A[i] as present or true.
Traverse the binary array again
Index of any bin entry that is not present or false is your missing integer
~
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
int solution(int A[], int N) {
// write your code in C99 (gcc 6.2.0)
int i;
bool *bin = (bool *)calloc((N+1),sizeof(bool));
for (i = 0; i < N; i++)
{
if (A[i] > 0 && A[i] < N+1)
{
bin[A[i]] = true;
}
}
for (i = 1; i < N+1; i++)
{
if (bin[i] == false)
{
break;
}
}
return i;
}
May be helpful, I am using arithmetic progression to calculate the sum, and using binary searach the element is fetched. checked with array of couple of hundred values works good. As there is one for loop and itression in step of 2, O(n/2) or less
def Missingelement (A):
B = [x for x in range(1,max(A)+1,1)]
n1 = len(B) - 1
begin = 0
end = (n1)//2
result = 0
print(A)
print(B)
if (len(A) < len(B)):
for i in range(2,n1,2):
if BinSum(A,begin,end) > BinSum(B,begin,end) :
end = (end + begin)//2
if (end - begin) <= 1 :
result=B[begin + 1 ]
elif BinSum(A,begin,end) == BinSum(B,begin,end):
r = end - begin
begin = end
end = (end + r)
if begin == end :
result=B[begin + 1 ]
return result
def BinSum(C,begin,end):
n = (end - begin)
if end >= len(C):
end = len(C) - 1
sum = n*((C[begin]+C[end])/2)
return sum
def main():
A=[1,2,3,5,6,7,9,10,11,12,14,15]
print ("smallest number missing is ",Missingelement(A))
if __name__ == '__main__': main()
Code for C, in fact, this can be used for any programming language without any change in the logic.
Logic is sum of N number is N*(N+1)/2.
int solution(int A[], int N) {
// write your code in C99
long long sum=0;
long long i;
long long Nsum=0;
for(i=0;i<N;i++){
sum=sum + (long long)A[i];
}
if (N%2==0){
Nsum= (N+1)*((N+2)/2);
return (int)(Nsum-sum);
}
else{
Nsum= ((N+1)/2)*(N+2);
return (int)(Nsum-sum);
}
}
This gave the 100/100 score.
This solution gets 100/100 on the test:
class Solution {
public int solution(int[] A) {
int x = 0;
while (x < A.length) {
// Keep swapping the values into the matching array positions.
if (A[x] > 0 && A[x] <= A.length && A[A[x]-1] != A[x]) {
swap(A, x, A[x] - 1);
} else {
x++; // Just need to increment when current element and position match.
}
}
for (int y=0; y < A.length; y++) {
// Find first element that doesn't match position.
// Array is 0 based while numbers are 1 based.
if (A[y] != y + 1) {
return y + 1;
}
}
return A.length + 1;
}
private void swap (int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
100% in PHP https://codility.com/demo/results/trainingKFXWKW-56V/
function solution($A){
$A = array_unique($A);
sort($A);
if (empty($A)) return 1;
if (max($A) <= 0) return 1;
if (max($A) == 1) return 2;
if (in_array(1, $A)) {
$A = array_slice($A, array_search(1, $A)); // from 0 to the end
array_unshift($A, 0); // Explanation 6a
if ( max($A) == array_search(max($A), $A)) return max($A) + 1; // Explanation 6b
for ($i = 1; $i <= count($A); $i++){
if ($A[$i] != $i) return $i; // Explanation 6c
}
} else {
return 1;
}
}
// Explanation
remove all duplicates
sort from min to max
if the array is empty return 1
if max of array is zero or less, return 1
if max of array is 1, return 2 // next positive integer
all other cases:
6a) split the array from value 1 to the end and add 0 before first number
6b) if the value of last element of array is the max of array, then the array is ascending so we return max + 1 // next positive integer
6c) if the array is not ascending, we find a missing number by a function for: if key of element is not as value the element but it should be (A = [0=>0, 1=>1,2=>3,...]), we return the key, because we expect the key and value to be equal.
Here is my solution, it Yields 88% in evaluation- Time is O(n), Correctness 100%, Performance 75%. REMEMBER - it is possible to have an array of all negative numbers, or numbers that exceed 100,000. Most of the above solutions (with actual code) yield much lower scores, or just do not work. Others seem to be irrelevant to the Missing Integer problem presented on Codility.
int compare( const void * arg1, const void * arg2 )
{
return *((int*)arg1) - *((int*)arg2);
}
solution( int A[], int N )
{
// Make a copy of the original array
// So as not to disrupt it's contents.
int * A2 = (int*)malloc( sizeof(int) * N );
memcpy( A2, A1, sizeof(int) * N );
// Quick sort it.
qsort( &A2[0], N, sizeof(int), compare );
// Start out with a minimum of 1 (lowest positive number)
int min = 1;
int i = 0;
// Skip past any negative or 0 numbers.
while( (A2[i] < 0) && (i < N )
{
i++;
}
// A variable to tell if we found the current minimum
int found;
while( i < N )
{
// We have not yet found the current minimum
found = 0;
while( (A2[i] == min) && (i < N) )
{
// We have found the current minimum
found = 1;
// move past all in the array that are that minimum
i++;
}
// If we are at the end of the array
if( i == N )
{
// Increment min once more and get out.
min++;
break;
}
// If we found the current minimum in the array
if( found == 1 )
{
// progress to the next minimum
min++;
}
else
{
// We did not find the current minimum - it is missing
// Get out - the current minimum is the missing one
break;
}
}
// Always free memory.
free( A2 );
return min;
}
My 100/100 solution
public int solution(int[] A) {
Arrays.sort(A);
for (int i = 1; i < 1_000_000; i++) {
if (Arrays.binarySearch(A, i) < 0){
return i;
}
}
return -1;
}
static int spn(int[] array)
{
int returnValue = 1;
int currentCandidate = 2147483647;
foreach (int item in array)
{
if (item > 0)
{
if (item < currentCandidate)
{
currentCandidate = item;
}
if (item <= returnValue)
{
returnValue++;
}
}
}
return returnValue;
}

Print all palindromes of size greater than equal to 3 of a given string [duplicate]

If the input is 'abba' then the possible palindromes are a, b, b, a, bb, abba.
I understand that determining if string is palindrome is easy. It would be like:
public static boolean isPalindrome(String str) {
int len = str.length();
for(int i=0; i<len/2; i++) {
if(str.charAt(i)!=str.charAt(len-i-1) {
return false;
}
return true;
}
But what is the efficient way of finding palindrome substrings?
This can be done in O(n), using Manacher's algorithm.
The main idea is a combination of dynamic programming and (as others have said already) computing maximum length of palindrome with center in a given letter.
What we really want to calculate is radius of the longest palindrome, not the length.
The radius is simply length/2 or (length - 1)/2 (for odd-length palindromes).
After computing palindrome radius pr at given position i we use already computed radiuses to find palindromes in range [i - pr ; i]. This lets us (because palindromes are, well, palindromes) skip further computation of radiuses for range [i ; i + pr].
While we search in range [i - pr ; i], there are four basic cases for each position i - k (where k is in 1,2,... pr):
no palindrome (radius = 0) at i - k
(this means radius = 0 at i + k, too)
inner palindrome, which means it fits in range
(this means radius at i + k is the same as at i - k)
outer palindrome, which means it doesn't fit in range
(this means radius at i + k is cut down to fit in range, i.e because i + k + radius > i + pr we reduce radius to pr - k)
sticky palindrome, which means i + k + radius = i + pr
(in that case we need to search for potentially bigger radius at i + k)
Full, detailed explanation would be rather long. What about some code samples? :)
I've found C++ implementation of this algorithm by Polish teacher, mgr Jerzy Wałaszek.
I've translated comments to english, added some other comments and simplified it a bit to be easier to catch the main part.
Take a look here.
Note: in case of problems understanding why this is O(n), try to look this way:
after finding radius (let's call it r) at some position, we need to iterate over r elements back, but as a result we can skip computation for r elements forward. Therefore, total number of iterated elements stays the same.
Perhaps you could iterate across potential middle character (odd length palindromes) and middle points between characters (even length palindromes) and extend each until you cannot get any further (next left and right characters don't match).
That would save a lot of computation when there are no many palidromes in the string. In such case the cost would be O(n) for sparse palidrome strings.
For palindrome dense inputs it would be O(n^2) as each position cannot be extended more than the length of the array / 2. Obviously this is even less towards the ends of the array.
public Set<String> palindromes(final String input) {
final Set<String> result = new HashSet<>();
for (int i = 0; i < input.length(); i++) {
// expanding even length palindromes:
expandPalindromes(result,input,i,i+1);
// expanding odd length palindromes:
expandPalindromes(result,input,i,i);
}
return result;
}
public void expandPalindromes(final Set<String> result, final String s, int i, int j) {
while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
result.add(s.substring(i,j+1));
i--; j++;
}
}
So, each distinct letter is already a palindrome - so you already have N + 1 palindromes, where N is the number of distinct letters (plus empty string). You can do that in single run - O(N).
Now, for non-trivial palindromes, you can test each point of your string to be a center of potential palindrome - grow in both directions - something that Valentin Ruano suggested.
This solution will take O(N^2) since each test is O(N) and number of possible "centers" is also O(N) - the center is either a letter or space between two letters, again as in Valentin's solution.
Note, there is also O(N) solution to your problem, based on Manacher's algoritm (article describes "longest palindrome", but algorithm could be used to count all of them)
I just came up with my own logic which helps to solve this problem.
Happy coding.. :-)
System.out.println("Finding all palindromes in a given string : ");
subPal("abcacbbbca");
private static void subPal(String str) {
String s1 = "";
int N = str.length(), count = 0;
Set<String> palindromeArray = new HashSet<String>();
System.out.println("Given string : " + str);
System.out.println("******** Ignoring single character as substring palindrome");
for (int i = 2; i <= N; i++) {
for (int j = 0; j <= N; j++) {
int k = i + j - 1;
if (k >= N)
continue;
s1 = str.substring(j, i + j);
if (s1.equals(new StringBuilder(s1).reverse().toString())) {
palindromeArray.add(s1);
}
}
}
System.out.println(palindromeArray);
for (String s : palindromeArray)
System.out.println(s + " - is a palindrome string.");
System.out.println("The no.of substring that are palindrome : "
+ palindromeArray.size());
}
Output:-
Finding all palindromes in a given string :
Given string : abcacbbbca
******** Ignoring single character as substring palindrome ********
[cac, acbbbca, cbbbc, bb, bcacb, bbb]
cac - is a palindrome string.
acbbbca - is a palindrome string.
cbbbc - is a palindrome string.
bb - is a palindrome string.
bcacb - is a palindrome string.
bbb - is a palindrome string.
The no.of substring that are palindrome : 6
I suggest building up from a base case and expanding until you have all of the palindomes.
There are two types of palindromes: even numbered and odd-numbered. I haven't figured out how to handle both in the same way so I'll break it up.
1) Add all single letters
2) With this list you have all of the starting points for your palindromes. Run each both of these for each index in the string (or 1 -> length-1 because you need at least 2 length):
findAllEvenFrom(int index){
int i=0;
while(true) {
//check if index-i and index+i+1 is within string bounds
if(str.charAt(index-i) != str.charAt(index+i+1))
return; // Here we found out that this index isn't a center for palindromes of >=i size, so we can give up
outputList.add(str.substring(index-i, index+i+1));
i++;
}
}
//Odd looks about the same, but with a change in the bounds.
findAllOddFrom(int index){
int i=0;
while(true) {
//check if index-i and index+i+1 is within string bounds
if(str.charAt(index-i-1) != str.charAt(index+i+1))
return;
outputList.add(str.substring(index-i-1, index+i+1));
i++;
}
}
I'm not sure if this helps the Big-O for your runtime, but it should be much more efficient than trying each substring. Worst case would be a string of all the same letter which may be worse than the "find every substring" plan, but with most inputs it will cut out most substrings because you can stop looking at one once you realize it's not the center of a palindrome.
I tried the following code and its working well for the cases
Also it handles individual characters too
Few of the cases which passed:
abaaa --> [aba, aaa, b, a, aa]
geek --> [g, e, ee, k]
abbaca --> [b, c, a, abba, bb, aca]
abaaba -->[aba, b, abaaba, a, baab, aa]
abababa -->[aba, babab, b, a, ababa, abababa, bab]
forgeeksskeegfor --> [f, g, e, ee, s, r, eksske, geeksskeeg,
o, eeksskee, ss, k, kssk]
Code
static Set<String> set = new HashSet<String>();
static String DIV = "|";
public static void main(String[] args) {
String str = "abababa";
String ext = getExtendedString(str);
// will check for even length palindromes
for(int i=2; i<ext.length()-1; i+=2) {
addPalindromes(i, 1, ext);
}
// will check for odd length palindromes including individual characters
for(int i=1; i<=ext.length()-2; i+=2) {
addPalindromes(i, 0, ext);
}
System.out.println(set);
}
/*
* Generates extended string, with dividors applied
* eg: input = abca
* output = |a|b|c|a|
*/
static String getExtendedString(String str) {
StringBuilder builder = new StringBuilder();
builder.append(DIV);
for(int i=0; i< str.length(); i++) {
builder.append(str.charAt(i));
builder.append(DIV);
}
String ext = builder.toString();
return ext;
}
/*
* Recursive matcher
* If match is found for palindrome ie char[mid-offset] = char[mid+ offset]
* Calculate further with offset+=2
*
*
*/
static void addPalindromes(int mid, int offset, String ext) {
// boundary checks
if(mid - offset <0 || mid + offset > ext.length()-1) {
return;
}
if (ext.charAt(mid-offset) == ext.charAt(mid+offset)) {
set.add(ext.substring(mid-offset, mid+offset+1).replace(DIV, ""));
addPalindromes(mid, offset+2, ext);
}
}
Hope its fine
public class PolindromeMyLogic {
static int polindromeCount = 0;
private static HashMap<Character, List<Integer>> findCharAndOccurance(
char[] charArray) {
HashMap<Character, List<Integer>> map = new HashMap<Character, List<Integer>>();
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
if (map.containsKey(c)) {
List list = map.get(c);
list.add(i);
} else {
List list = new ArrayList<Integer>();
list.add(i);
map.put(c, list);
}
}
return map;
}
private static void countPolindromeByPositions(char[] charArray,
HashMap<Character, List<Integer>> map) {
map.forEach((character, list) -> {
int n = list.size();
if (n > 1) {
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (list.get(i) + 1 == list.get(j)
|| list.get(i) + 2 == list.get(j)) {
polindromeCount++;
} else {
char[] temp = new char[(list.get(j) - list.get(i))
+ 1];
int jj = 0;
for (int ii = list.get(i); ii <= list
.get(j); ii++) {
temp[jj] = charArray[ii];
jj++;
}
if (isPolindrome(temp))
polindromeCount++;
}
}
}
}
});
}
private static boolean isPolindrome(char[] charArray) {
int n = charArray.length;
char[] temp = new char[n];
int j = 0;
for (int i = (n - 1); i >= 0; i--) {
temp[j] = charArray[i];
j++;
}
if (Arrays.equals(charArray, temp))
return true;
else
return false;
}
public static void main(String[] args) {
String str = "MADAM";
char[] charArray = str.toCharArray();
countPolindromeByPositions(charArray, findCharAndOccurance(charArray));
System.out.println(polindromeCount);
}
}
Try out this. Its my own solution.
// Maintain an Set of palindromes so that we get distinct elements at the end
// Add each char to set. Also treat that char as middle point and traverse through string to check equality of left and right char
static int palindrome(String str) {
Set<String> distinctPln = new HashSet<String>();
for (int i=0; i<str.length();i++) {
distinctPln.add(String.valueOf(str.charAt(i)));
for (int j=i-1, k=i+1; j>=0 && k<str.length(); j--, k++) {
// String of lenght 2 as palindrome
if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(j)))) {
distinctPln.add(str.substring(j,i+1));
}
// String of lenght 2 as palindrome
if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(k)))) {
distinctPln.add(str.substring(i,k+1));
}
if ( (new Character(str.charAt(j))).equals(new Character(str.charAt(k)))) {
distinctPln.add(str.substring(j,k+1));
} else {
continue;
}
}
}
Iterator<String> distinctPlnItr = distinctPln.iterator();
while ( distinctPlnItr.hasNext()) {
System.out.print(distinctPlnItr.next()+ ",");
}
return distinctPln.size();
}
Code is to find all distinct substrings which are palindrome.
Here is the code I tried. It is working fine.
import java.util.HashSet;
import java.util.Set;
public class SubstringPalindrome {
public static void main(String[] args) {
String s = "abba";
checkPalindrome(s);
}
public static int checkPalindrome(String s) {
int L = s.length();
int counter =0;
long startTime = System.currentTimeMillis();
Set<String> hs = new HashSet<String>();
// add elements to the hash set
System.out.println("Possible substrings: ");
for (int i = 0; i < L; ++i) {
for (int j = 0; j < (L - i); ++j) {
String subs = s.substring(j, i + j + 1);
counter++;
System.out.println(subs);
if(isPalindrome(subs))
hs.add(subs);
}
}
System.out.println("Total possible substrings are "+counter);
System.out.println("Total palindromic substrings are "+hs.size());
System.out.println("Possible palindromic substrings: "+hs.toString());
long endTime = System.currentTimeMillis();
System.out.println("It took " + (endTime - startTime) + " milliseconds");
return hs.size();
}
public static boolean isPalindrome(String s) {
if(s.length() == 0 || s.length() ==1)
return true;
if(s.charAt(0) == s.charAt(s.length()-1))
return isPalindrome(s.substring(1, s.length()-1));
return false;
}
}
OUTPUT:
Possible substrings:
a
b
b
a
ab
bb
ba
abb
bba
abba
Total possible substrings are 10
Total palindromic substrings are 4
Possible palindromic substrings: [bb, a, b, abba]
It took 1 milliseconds

Run length encoding using O(1) space

Can we do the run-length encoding in place(assuming the input array is very large)
We can do for the cases such as AAAABBBBCCCCDDDD
A4B4C4D4
But how to do it for the case such as ABCDEFG?
where the output would be A1B1C1D1E1F1G1
My first thought was to start encoding from the end, so we will use the free space (if any), after that we can shift the encoded array to the start. A problem with this approach is that it will not work for AAAAB, because there is no free space (it's not needed for A4B1) and we will try to write AAAAB1 on the first iteration.
Below is corrected solution:
(let's assume the sequence is AAABBC)
encode all groups with two or more elements and leave the rest unchanged (this will not increase length of the array) -> A3_B2C
shift everything right eliminating empty spaces after first step -> _A3B2C
encode the array from the start (reusing the already encoded groups of course) -> A3B2C1
Every step is O(n) and as far as I can see only constant additional memory is needed.
Limitations:
Digits are not supported, but that anyway would create problems with decoding as Petar Petrov mentioned.
We need some kind of "empty" character, but this can be worked around by adding zeros: A03 instead of A3_
C++ solution O(n) time O(1) space
string runLengthEncode(string str)
{
int len = str.length();
int j=0,k=0,cnt=0;
for(int i=0;i<len;i++)
{
j=i;
cnt=1;
while(i<len-1 && str[i]==str[i+1])
{
i++;
cnt++;
}
str[k++]=str[j];
string temp =to_string(cnt);
for(auto m:temp)
str[k++] = m;
}
str.resize(k);
return str;
}
null is used to indicate which items are empty and will be ignored for encoding. Also you can't encode digits (AAA2222 => A324 => 324 times 'A', but it's A3;24). Your question opens more questions.
Here's a "solution" in C#
public static void Encode(string[] input)
{
var writeIndex = 0;
var i = 0;
while (i < input.Length)
{
var symbol = input[i];
if (symbol == null)
{
break;
}
var nextIndex = i + 1;
var offset = 0;
var count = CountSymbol(input, symbol, nextIndex) + 1;
if (count == 1)
{
ShiftRight(input, nextIndex);
offset++;
}
input[writeIndex++] = symbol;
input[writeIndex++] = count.ToString();
i += count + offset;
}
Array.Clear(input, writeIndex, input.Length - writeIndex);
}
private static void ShiftRight(string[] input, int nextIndex)
{
var count = CountSymbol(input, null, nextIndex, (a, b) => a != b);
Array.Copy(input, nextIndex, input, nextIndex + 1, count);
}
private static int CountSymbol(string[] input, string symbol, int nextIndex)
{
return CountSymbol(input, symbol, nextIndex, (a, b) => a == b);
}
private static int CountSymbol(string[] input, string symbol, int nextIndex, Func<string, string, bool> cmp)
{
var count = 0;
var i = nextIndex;
while (i < input.Length && cmp(input[i], symbol))
{
count++;
i++;
}
return count;
}
The 1st solution does not take care of single characters. For example - 'Hi!' will not work. I've used totally different approach, used 'insert()' functions to add inplace. This take care of everything, whether the total 'same' character is > 10 or >100 or = 1.
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
string name = "Hello Buddy!!";
int start = 0;
char distinct = name[0];
for(int i=1;i<name.length()+1;){
if(distinct!=name[i]){
string s = to_string(i-start);
name.insert(start+1,s);
name.erase(name.begin() + start + 1 + s.length(),name.begin() + s.length() + i);
i=start+s.length()+1;
start=i;
distinct=name[start];
continue;
}
i++;
}
cout<<name;
}
Suggest me if you find anything incorrect.
O(n), in-place RLE, I couldn't think better than this. It will not place a number, if chars occurence is just 1. Will also place a9a2, if the character comes 11 times.
void RLE(char *str) {
int len = strlen(str);
int count = 1, j = 0;
for (int i = 0; i < len; i++){
if (str[i] == str[i + 1])
count++;
else {
int times = count / 9;
int rem = count % 9;
for (int k = 0; k < times; k++) {
str[j++] = str[i];
_itoa(9, &str[j++], 10);
count = count - 9;
}
if (count > 1) {
str[j++] = str[i];
_itoa(rem, &str[j++], 10);
count = 1;
}
else
str[j++] = str[i];
}
}
cout << str;
}
I/P => aaabcdeeeefghijklaaaaa
O/P => a3bcde4fghijkla5
Inplace solution using c++ ( assumes length of encoding string is not more than actual string length):
#include <bits/stdc++.h>
#include<stdlib.h>
using namespace std;
void replacePattern(char *str)
{
int len = strlen(str);
if (len == 0)
return;
int i = 1, j = 1;
int count;
// for each character
while (str[j])
{
count = 1;
while (str[j] == str[j-1])
{
j = j + 1;
count++;
}
while(count > 0) {
int rem = count%10;
str[i++] = to_string(rem)[0];
count = count/10;
}
// copy character at current position j
// to position i and increment i and j
if (str[j])
str[i++] = str[j++];
}
// add a null character to terminate string
if(str[len-1] != str[len-2]) {
str[i] = '1';
i++;
}
str[i] = '\0';
}
// Driver code
int main()
{
char str[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabccccc";
replacePattern(str);
cout << str;
return 0;
}

Minimum window width in string x that contains all characters of string y

Find minimum window width in string x that contains all characters of another string y. For example:
String x = "coobdafceeaxab"
String y = "abc"
The answer should be 5, because the shortest substring in x that contains all three letters of y is "bdafc".
I can think of a naive solution with complexity O(n^2 * log(m)), where n = len(x) and m = len(y). Can anyone suggest a better solution? Thanks.
Update: now think of it, if I change my set to tr1::unordered_map, then I can cut the complexity down to O(n^2), because insertion and deletion should both be O(1).
time: O(n) (One pass)
space: O(k)
This is how I would do it:
Create a hash table for all the characters from string Y. (I assume all characters are different in Y).
First pass:
Start from first character of string X.
update hash table, for exa: for key 'a' enter location (say 1).
Keep on doing it until you get all characters from Y (until all key in hash table has value).
If you get some character again, update its newer value and erase older one.
Once you have first pass, take smallest value from hash table and biggest value.
Thats the minimum window observed so far.
Now, go to next character in string X, update hash table and see if you get smaller window.
Edit:
Lets take an example here:
String x = "coobdafceeaxab"
String y = "abc"
First initialize a hash table from characters of Y.
h[a] = -1
h[b] = -1
h[c] = -1
Now, Start from first character of X.
First character is c, h[c] = 0
Second character (o) is not part of hash, skip it.
..
Fourth character (b), h[b] = 3
..
Sixth character(a), enter hash table h[a] = 5.
Now, all keys from hash table has some value.
Smallest value is 0 (of c) and highest value is 5 (of a), minimum window so far is 6 (0 to 5).
First pass is done.
Take next character. f is not part of hash table, skip it.
Next character (c), update hash table h[c] = 7.
Find new window, smallest value is 3 (of b) and highest value is 7 (of c).
New window is 3 to 7 => 5.
Keep on doing it till last character of string X.
I hope its clear now.
Edit
There are some concerns about finding max and min value from hash.
We can maintain sorted Link-list and map it with hash table.
Whenever any element from Link list changes, it should be re-mapped to hash table.
Both these operation are O(1)
Total space would be m+m
Edit
Here is small visualisation of above problem:
For "coobdafceeaxab" and "abc"
step-0:
Initial doubly linked-list = NULL
Initial hash-table = NULL
step-1:
Head<->[c,0]<->tail
h[c] = [0, 'pointer to c node in LL']
step-2:
Head<->[c,0]<->[b,3]<->tail
h[c] = [0, 'pointer to c node in LL'], h[b] = [3, 'pointer to b node in LL'],
Step-3:
Head<->[c,0]<->[b,3]<->[a,5]<->tail
h[c] = [0, 'pointer to c node in LL'], h[b] = [3, 'pointer to b node in LL'], h[a] = [5, 'pointer to a node in LL']
Minimum Window => difference from tail and head => (5-0)+1 => Length: 6
Step-4:
Update entry of C to index 7 here. (Remove 'c' node from linked-list and append at the tail)
Head<->[b,3]<->[a,5]<->[c,7]<->tail
h[c] = [7, 'new pointer to c node in LL'], h[b] = [3, 'pointer to b node in LL'], h[a] = [5, 'pointer to a node in LL'],
Minimum Window => difference from tail and head => (7-3)+1 => Length: 5
And so on..
Note that above Linked-list update and hash table update are both O(1).
Please correct me if I am wrong..
Summary:
TIme complexity: O(n) with one pass
Space Complexity: O(k) where k is length of string Y
I found this very nice O(N) time complexity version here http://leetcode.com/2010/11/finding-minimum-window-in-s-which.html, and shortened it slightly (removed continue in a first while , which allowed to simplify condition for the second while loop). Note, that this solution allows for duplicates in the second string, while many of the above answers do not.
private static String minWindow(String s, String t) {
int[] needToFind = new int[256];
int[] hasFound = new int[256];
for(int i = 0; i < t.length(); ++i) {
needToFind[t.charAt(i)]++;
}
int count = 0;
int minWindowSize = Integer.MAX_VALUE;
int start = 0, end = -1;
String window = "";
while (++end < s.length()) {
char c = s.charAt(end);
if(++hasFound[c] <= needToFind[c]) {
count++;
}
if(count < t.length()) continue;
while (hasFound[s.charAt(start)] > needToFind[s.charAt(start)]) {
hasFound[s.charAt(start++)]--;
}
if(end - start + 1 < minWindowSize) {
minWindowSize = end - start + 1;
window = s.substring(start, end + 1);
}
}
return window;
}
Here's my solution in C++:
int min_width(const string& x, const set<char>& y) {
vector<int> at;
for (int i = 0; i < x.length(); i++)
if (y.count(x[i]) > 0)
at.push_back(i);
int ret = x.size();
int start = 0;
map<char, int> count;
for (int end = 0; end < at.size(); end++) {
count[x[at[end]]]++;
while (count[x[at[start]]] > 1)
count[x[at[start++]]]--;
if (count.size() == y.size() && ret > at[end] - at[start] + 1)
ret = at[end] - at[start] + 1;
}
return ret;
}
Edit: Here's an implementation of Jack's idea. It's the same time complexity as mine, but without the inner loop that confuses you.
int min_width(const string& x, const set<char>& y) {
int ret = x.size();
map<char, int> index;
set<int> index_set;
for (int j = 0; j < x.size(); j++) {
if (y.count(x[j]) > 0) {
if (index.count(x[j]) > 0)
index_set.erase(index[x[j]]);
index_set.insert(j);
index[x[j]] = j;
if (index.size() == y.size()) {
int i = *index_set.begin();
if (ret > j-i+1)
ret = j-i+1;
}
}
}
return ret;
}
In Java it can be implemented nicely with LinkedHashMap:
static int minWidth(String x, HashSet<Character> y) {
int ret = x.length();
Map<Character, Integer> index = new LinkedHashMap<Character, Integer>();
for (int j = 0; j < x.length(); j++) {
char ch = x.charAt(j);
if (y.contains(ch)) {
index.remove(ch);
index.put(ch, j);
if (index.size() == y.size()) {
int i = index.values().iterator().next();
if (ret > j - i + 1)
ret = j - i + 1;
}
}
}
return ret;
}
All operations inside the loop take constant time (assuming hashed elements disperse properly).
There is an O(n solution to this problem). It very well described in this article.
http://www.leetcode.com/2010/11/finding-minimum-window-in-s-which.html
Hope it helps.
This is my solution in C++, just for reference.
Update: originally I used std::set, now I change it to tr1::unordered_map to cut complexity down to n^2, otherwise these two implementations look pretty similar, to prevent this post from getting too long, I only list the improved solution.
#include <iostream>
#include <tr1/unordered_map>
#include <string>
using namespace std;
using namespace std::tr1;
typedef tr1::unordered_map<char, int> hash_t;
// Returns min substring width in which sentence contains all chars in word
// Returns sentence's length + 1 if not found
size_t get_min_width(const string &sent, const string &word) {
size_t min_size = sent.size() + 1;
hash_t char_set; // char set that word contains
for (size_t i = 0; i < word.size(); i++) {
char_set.insert(hash_t::value_type(word[i], 1));
}
for (size_t i = 0; i < sent.size() - word.size(); i++) {
hash_t s = char_set;
for (size_t j = i; j < min(j + min_size, sent.size()); j++) {
s.erase(sent[j]);
if (s.empty()) {
size_t size = j - i + 1;
if (size < min_size) min_size = size;
break;
}
}
}
return min_size;
}
int main() {
const string x = "coobdafceeaxab";
const string y = "abc";
cout << get_min_width(x, y) << "\n";
}
An implementation of Jack's idea.
public int smallestWindow(String str1, String str2){
if(str1==null || str2==null){
throw new IllegalArgumentException();
}
Map<String, Node> map=new HashMap<String, Node>();
Node head=null, current=null;
for(int i=0;i<str1.length();i++){
char c=str1.charAt(i);
if(head==null){
head=new Node(c);
current=head;
map.put(String.valueOf(c), head);
}
else{
current.next=new Node(c);
current.next.pre=current;
current=current.next;
map.put(String.valueOf(c), current);
}
}
Node end=current;
int min=Integer.MAX_VALUE;
int count=0;
for(int i=0;i<str2.length();i++){
char c = str2.charAt(i);
Node n=map.get(String.valueOf(c));
if(n!=null){
if(n.index==Integer.MAX_VALUE){
count++;
}
n.index=i;
if(n==head){
Node temp=head;
head=head.next;
if(head==null){//one node
return 1;
}
head.pre=null;
temp.pre=end;
end.next=temp;
temp.next=null;
end=temp;
}
else if(end!=n){
n.pre.next=n.next;
n.next.pre=n.pre;
n.pre=end;
n.next=null;
end.next=n;
end=n;
}
if(count==str1.length()){
min=Math.min(end.index-head.index+1, min);
}
}
}
System.out.println(map);
return min;
}
Simple java solution using the sliding window. Extending NitishMD's idea above:
public class StringSearchDemo {
public String getSmallestSubsetOfStringContaingSearchString(String toMatch,
String inputString) {
if (inputString.isEmpty() || toMatch.isEmpty()) {
return null;
}
// List<String> results = new ArrayList<String>(); // optional you can comment this out
String smallestMatch = "";
// String largestMatch = "";
int startPointer = 0, endPointer = 1;
HashMap<Character, Integer> toMatchMap = new HashMap<Character, Integer>();
for (char c : toMatch.toCharArray()) {
if (toMatchMap.containsKey(c)) {
toMatchMap.put(c, (toMatchMap.get(c) + 1));
} else {
toMatchMap.put(c, 1);
}
}
int totalCount = getCountofMatchingString(toMatchMap, toMatch);
for (int i = 0; i < inputString.length();) {
if (!toMatchMap.containsKey(inputString.charAt(i))) {
endPointer++;
i++;
continue;
}
String currentSubString = inputString.substring(startPointer,
endPointer);
if (getCountofMatchingString(toMatchMap, currentSubString) >= totalCount) {
// results.add(currentSubString); // optional you can comment this out
if (smallestMatch.length() > currentSubString.length()) {
smallestMatch = currentSubString;
} else if (smallestMatch.isEmpty()) {
smallestMatch = currentSubString;
}
// if (largestMatch.length() < currentSubString.length()) {
// largestMatch = currentSubString;
// }
startPointer++;
} else {
endPointer++;
i++;
}
}
// System.out.println("all possible combinations = " + results); // optional, you can comment this out
// System.out.println("smallest result = " + smallestMatch);
// System.out.println("largest result = " + largestMatch);
return smallestMatch;
}
public int getCountofMatchingString(HashMap<Character, Integer> toMatchMap,
String toMatch) {
int match = 0;
HashMap<Character, Integer> localMap = new HashMap<Character, Integer>();
for (char c : toMatch.toCharArray()) {
if (toMatchMap.containsKey(c)) {
if (localMap.containsKey(c)) {
if (localMap.get(c) < toMatchMap.get(c)) {
localMap.put(c, (localMap.get(c) + 1));
match++;
}
} else {
localMap.put(c, 1);
match++;
}
}
}
return match;
}
public static void main(String[] args) {
String inputString = "zxaddbddxyy由ccbbwwaay漢字由来";
String matchCriteria = "a由";
System.out.println("input=" + matchCriteria);
System.out.println("matchCriteria=" + inputString);
String result = (new StringSearchDemo())
.getSmallestSubsetOfStringContaingSearchString(matchCriteria, inputString);
System.out.println("smallest possbile match = " + result);
}
}

Resources