Valid Palindrome, Palindrome Number, Scramble String, Reverse Binary, Interleaving String

Valid Palindrome

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
For example,
“A man, a plan, a canal: Panama” is a palindrome.
“race a car” is not a palindrome.
Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.
For the purpose of this problem, we define empty string as valid palindrome.

  • Only count numeric and alphabetical, ignore cases
  • Empty String count as palindrome
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public boolean isPalindrome(String s) {
    if(s==null||s.length()==0) return true;
    s=s.toUpperCase();
    int l=0, r=s.length()-1;
    while(l<r){
    Character tmpl=s.charAt(l), tmpr=s.charAt(r);
    if(!(tmpl>='0'&& tmpl<='9'||tmpl>='A'&&tmpl<='Z')) {l++; continue;}
    else if(!(tmpr>='0'&& tmpr<='9'||tmpr>='A'&&tmpr<='Z')) {r--;continue;}
    else{
    if(tmpl.equals(tmpr)){l++;r--;}
    else return false;
    }
    }
    return true;
    }

    Palindrome Number

    Determine whether an integer is a palindrome. Do this without extra space.
    Could negative integers be palindromes? (ie, -1)
    If you are thinking of converting the integer to string, note the restriction of using extra space.
    You could also try reversing an integer. However, if you have solved the problem “Reverse Integer”, you know that the reversed integer might overflow. How would you handle such case?
    There is a more generic way of solving this problem.

    Solution

    refer my solution to reverse integer.

  • reverse the number. If the number is the same as its reversed, then it must be a palindrome.
  • negative integers as non-palindromes.
  • Even thought this passed OJ, didn’t deal with overflow issues.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public boolean isPalindrome(int x) {
    int res=0,orig=x;
    if(x<0) return false;
    while(x!=0){
    res=res*10+x%10;
    x=x/10;
    }
    return res==orig ? true:false;
    }

    Another Solution

    First, compare the first and last digit. If they are not the same, it must not be a palindrome. If they are the same, chop off one digit from both ends and continue until you have no digits left, which you conclude that it must be a palindrome.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public boolean isPalindrome2(int x) {
    if (x < 0) return false;
    int div = 1;
    while (x / div >= 10) {
    div *= 10;
    }
    while (x != 0) {
    int l = x / div;
    int r = x % 10;
    if (l != r) return false;
    x = (x % div) / 10;
    div /= 100;
    }
    return true;
    }

    Scramble String

    Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
    Below is one possible representation of s1 = “great”:

    1
    2
    3
    4
    5
    6
    7
    great
    / \
    gr eat
    / \ / \
    g r e at
    / \
    a t

    To scramble the string, we may choose any non-leaf node and swap its two children.
    For example, if we choose the node “gr” and swap its two children, it produces a scrambled string “rgeat”.

    1
    2
    3
    4
    5
    6
    7
    rgeat
    / \
    rg eat
    / \ / \
    r g e at
    / \
    a t

    We say that “rgeat” is a scrambled string of “great”.
    Similarly, if we continue to swap the children of nodes “eat” and “at”, it produces a scrambled string “rgtae”.

    1
    2
    3
    4
    5
    6
    7
    rgtae
    / \
    rg tae
    / \ / \
    r g ta e
    / \
    t a

    We say that “rgtae” is a scrambled string of “great”.
    Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.

    Iterative Solution

    If string s1 and s2 are scramble strings, there must be a point(i) that breaks s1 to two parts s11, s12, and a point(l-i) that breaks s2 to two parts, s21, s22, and isScramble(s11, s21) && isScramble(s12, s22) is true, or isScramble(s11, s22) && isScramble(s12, s21) is true.

    Cases to consider to avoid LTE:

  • If the lengths of two strings are different, they can’t be scramble.
  • If the characters in two strings are different, they can’t be scramble either.
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public boolean isScramble(String s1, String s2) {
    //check length
    if(s1.length()!=s2.length()) return false;
    int i=0;int L = s1.length();
    if(s1.equals(s2)) return true;
    // check letters
    int[] count=new int[26];
    for(;i<L;i++){
    count[s1.charAt(i)-'a']++;
    count[s2.charAt(i)-'a']--;
    }
    for(i=0;i<26;i++){
    if(count[i]!=0) return false;
    }
    //check scramble, starting from 1
    for(i=1;i<L;i++){
    String s11=s1.substring(0, i);
    String s12=s1.substring(i);
    String s21=s2.substring(0,i);
    String s22=s2.substring(i);
    if(isScramble(s11,s21)&&isScramble(s12,s22)) return true;
    else {
    s21=s2.substring(0,L-i);
    s22=s2.substring(L-i);
    if(isScramble(s11,s22)&&isScramble(s12,s21)) return true;
    }
    }return false;
    }

    DP Solution

  • t[i][j][len]=1 means that two substrings of length k, one starts from i of string s1, another one starts from j of string s2, are scramble
  • we are looking for t[0][0][L]
  • given a len, we can cut the substring in len-1 ways, if one of them proves to be scramble then t[i][j][k]=true
  • Changing Rule: t[i][j][k] && t[i+k][j+k][Len-k] || t[i][j+Len-k][k] && t[i+k][j][Len-k]
  • Time is O(n^4), space is O(n^3).
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public boolean isScramble(String s1, String s2) {
    if(s1.length()!=s2.length()) return false;
    if(s1.equals(s2)) return true;
    int L=s1.length();
    boolean [][][] t=new boolean[L][L][L+1];
    //init base value
    for(int i=0;i<L;i++){
    for(int j=0;j<L;j++){
    t[i][j][1] = s1.charAt(i)==s2.charAt(j);
    }
    }
    //calculate the whole table
    for(int len=2;len<=L;len++){
    for(int i=0;i<L-len+1;i++){
    for(int j=0;j<L-len+1;j++){
    for(int k=1;k<len;k++){
    //等号左右两边只要有一个是1就行了
    t[i][j][len] |= (t[i][j][k] && t[i+k][j+k][len-k] || t[i][j+len-k][k] && t[i+k][j][len-k]) ;
    }
    }
    }
    }
    //return the last value
    return t[0][0][L];
    }

    Reverse Binary

    1) 1010->0101 1111->0000

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public String ReverseBinary2(int d){
    int n=Integer.toBinaryString(d).length();
    String res="";
    System.out.println(" d "+d);
    while(d!=0){
    int tmp = 1-d & 0x01;
    System.out.println(" d "+Integer.toBinaryString(d) +" tmp "+tmp);
    res=tmp+res;
    d >>= 1;
    System.out.println(" d: "+d+ " b "+Integer.toBinaryString(d));
    }
    System.out.println(res);
    return res;
    }

    2) 1100->0011 1111->1111

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public String ReverseBinary(int d){
    int n=Integer.toBinaryString(d).length();
    StringBuffer sb=new StringBuffer();
    System.out.println(" d "+d);
    while(d!=0){
    sb.append(d ^ 0x01);
    System.out.println(" d "+d+" sb "+sb+ " "+0x01);
    d >>= 1;
    System.out.println(" d: "+d+ " b "+Integer.toBinaryString(d));
    }
    String s=sb.toString();
    System.out.println(" s: "+s);
    String res=Integer.valueOf(s, 2).toString();
    return res;
    }

    Interleaving String

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
    For example,
    Given:
    s1 = “aabcc”,
    s2 = “dbbca”,
    When s3 = “aadbbcbcac”, return true.
    When s3 = “aadbbbaccc”, return false.

    Recursive Solution

    Three pointers, four cases:

  • char at p3 equals to both p2, p1. either result could be true
  • char at p3 only equals to p2, increment these two pointers. If one of p1, p2 reached its length, just compare the rest substring
  • vice versa
  • char at p3 equals to none, break and return false
  • This solution is LTE, as expected…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public boolean isInterleave(String s1, String s2, String s3) {
    if(s1.length()+s2.length()!=s3.length()) return false;
    return rec(s1,0,s2,0,s3,0);
    }
    private boolean rec(String s1, int p1, String s2, int p2, String s3, int p3){
    if(p3==s3.length()) return true;
    if(p2==s2.length()) return s1.substring(p1).equals(s3.substring(p3));
    if(p1==s1.length()) return s2.substring(p2).equals(s3.substring(p3));
    if(s3.charAt(p3)==s1.charAt(p1) && s3.charAt(p3)==s2.charAt(p2))
    return rec(s1,p1+1,s2,p2,s3,p3+1) || rec(s1,p1,s2,p2+1,s3,p3+1);
    else if(s3.charAt(p3)==s1.charAt(p1))
    return rec(s1,p1+1,s2,p2,s3,p3+1);
    else if(s3.charAt(p3)==s2.charAt(p2))
    return rec(s1,p1,s2,p2+1,s3,p3+1);
    else return false;
    }

    DP Solution

    特么才一辈子都凑不粗来好么…

  • t[i][j] shows whether using the first i and j elements of s1, s2 can form the first i+j elements of s3.
  • Initialization: for t[s1+1][s2+1], the first column and row are set by comparing chars to target string, and the previous tuple.
  • Changing Rule: depends on top and left tuple. Set to true if current char in s1 equals to corresponding char in s3, and previous tuple is true.
  • Target: t[s1][s2]
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public boolean isInterleave(String s1, String s2, String s3) {
    if(s1.length()+s2.length()!=s3.length()) return false;
    boolean[][] t=new boolean[s1.length()+1][s2.length()+1];
    t[0][0]=true;
    for(int i=1;i<s1.length()+1;i++){
    t[i][0]= s1.charAt(i-1)==s3.charAt(i-1) && t[i-1][0];
    }
    for(int i=1;i<s2.length()+1;i++){
    t[0][i]= s2.charAt(i-1)==s3.charAt(i-1) && t[0][i-1];
    }
    //deduct the whole table
    for(int i=1; i<s1.length()+1;i++){
    for(int j=1;j<s2.length()+1;j++){
    t[i][j]= (t[i-1][j] && s1.charAt(i-1)==s3.charAt(i+j-1)) || (t[i][j-1] && s2.charAt(j-1)==s3.charAt(i+j-1));
    }
    }
    return t[s1.length()][s2.length()];
    }