package com.interview.leetcode.strings; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * Created_By: stefanie * Date: 14-11-14 * Time: 上午8:27 */ public class Palindrome { /** * validate the input s is palindrome or not. * only consider letter and digit, and have a boolean flag for case sensitive or not. */ public boolean valid(String s, boolean caseSensitive) { int i = 0, j = s.length() - 1; while (i < j) { while (i < j && !Character.isLetterOrDigit(s.charAt(i))) i++; while (i < j && !Character.isLetterOrDigit(s.charAt(j))) j--; if(caseSensitive){ if(s.charAt(i) != s.charAt(j)) return false; } else { if (Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(s.charAt(j))) return false; } i++; j--; } return true; } /** * Give a string s, calculate all the substring(i, j) is a palindrome or not */ public boolean[][] getPalindromeMatrix(String s){ boolean[][] matrix = new boolean[s.length()][s.length()]; for(int i = 0; i < s.length(); i++) matrix[i][i] = true; for(int len = 1; len < s.length(); len++){ for(int i = 0; i+len < s.length(); i++){ matrix[i][i+len] = (len == 1? true : matrix[i+1][i+len-1]) && s.charAt(i) == s.charAt(i + len); } } return matrix; } /** * Given a string, rearrange the string to a palindrome and return the palindrome if present or null */ public static String rearrange(String s){ if(s == null) return null; int[] marker = new int[256]; for(int i = 0; i < s.length(); i++) marker[s.charAt(i)]++; boolean hasOdd = false; char[] chars = new char[s.length()]; for(int offset = 0, i = 0; i < 256; i++){ while(marker[i] > 1){ chars[offset] = (char) i; chars[s.length() - 1 - offset] = (char) i; marker[i] = marker[i] - 2; offset++; } if(marker[i] == 1){ if(hasOdd) return null; chars[s.length()/2] = (char) i; //put in the center hasOdd = true; } } return String.valueOf(chars); } /** * Given a string S, find the longest palindromic substring in S. * You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. */ static class LongestPalindrome{ //Time O(N^2) Space O(N^2) public static String longestPalindromeDP(String str){ if(str == null || str.length() == 0) return ""; int max = 0, start = 0, end = 0; boolean[][] dp = new boolean[str.length()][str.length()]; for (int i = 0; i < str.length(); i++) dp[i][i] = true; //dp[i][j] = dp[i+1][j-1] && charAt(i) == charAt(j) for (int len = 1; len < str.length(); len++) { for (int i = 0; i + len < str.length(); i++) { dp[i][i + len] = (len == 1? true : dp[i + 1][i + len - 1]) && str.charAt(i) == str.charAt(i + len); if (dp[i][i + len] && len > max) { max = len; start = i; end = i + len; } } } return str.substring(start, end + 1); } //Time O(N^2) Space O(1) public static String longestPalindrome(String str){ int max = 1, start = 0, end = 0; for(int i = 0; i < str.length(); i++){ int len = 1; while(i -len >= 0 && i + len < str.length() && str.charAt(i-len) == str.charAt(i+len)){ if(2 * len + 1 > max){ max = 2 * len + 1; start = i - len; end = i + len; } len++; } len = 0; while(i - len >= 0 && i + len + 1 < str.length() && str.charAt(i - len) == str.charAt(i+len+1)){ if(2 * len + 2 > max){ max = 2 * len + 2; start = i - len; end = i + len + 1; } len++; } } return str.substring(start, end + 1); } } /** * Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. */ static class PalindromePartition{ public List<List<String>> partition(String s) { List<List<String>> partitions = new ArrayList<>(); if(s == null) return partitions; List<String> current = new ArrayList<>(); find(s, 0, current, partitions); return partitions; } public void find(String s, int offset, List<String> current, List<List<String>> partitions){ if(offset == s.length()){ //find a partition List<String> sol = new ArrayList<String>(); sol.addAll(current); partitions.add(sol); return; } for(int i = offset + 1; i <= s.length(); i++){ String prefix = s.substring(offset, i); if(isPalindrome(prefix)){ current.add(prefix); find(s, i, current, partitions); current.remove(current.size() - 1); } } } public boolean isPalindrome(String s){ for(int i = 0, j = s.length() - 1; i < j; i++, j--){ if(s.charAt(i) != s.charAt(j)) return false; } return true; } } /** * Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s. */ static class MinPalindromePartition{ //DP: // minCut[i] = min(minCut[j] + 1, if substring(j, i+1) is palindrome) // special case: substring(0, i+1) is palindrome, so minCut[i] = 0; public int minCut(String s){ if(s == null || s.length() == 1) return 0; boolean[][] isPalindrome = calculate(s); int[] minCut = new int[s.length()]; minCut[0] = 0; for(int i = 1; i < s.length(); i++){ minCut[i] = minCut[i-1] + 1; if(isPalindrome[0][i]) { minCut[i] = 0; continue; } for(int j = 1; j < i; j++){ if(isPalindrome[j][i]) minCut[i] = Math.min(minCut[i], minCut[j - 1] + 1); } } return minCut[s.length() - 1]; } //DP: // Init: isPalindrome[i][i] = true, isPalindrome[i-1][i] = s.charAt(i-1) == s.charAt(i); // Loop: len and start position i // isPalindrome[i][i+len] = isPalindome[i+1][i+len-1] && s.charAt(i) == s.charAt(i + len) public boolean[][] calculate(String s){ //substring(i, j + 1) is palindrome boolean[][] isPalindrome = new boolean[s.length()][s.length()]; for (int i = 0; i < s.length(); i++) isPalindrome[i][i] = true; for (int len = 1; len < s.length(); len++) { for (int i = 0; i + len < s.length(); i++) { isPalindrome[i][i + len] = (len == 1 ? true : isPalindrome[i + 1][i + len - 1]) && s.charAt(i) == s.charAt(i + len); } } return isPalindrome; } } /** * given a dict of words, find pair of words can concatenate to create a palindrome */ static class PairPalindrome{ public void findPairPalindrome(Set<String> dict){ for(String word : dict){ findPalindrome(word, dict); } } //for every word public void findPalindrome(String s, Set<String> dict){ //scan forward for(int i = 0; i < s.length(); i++){ String prefix = s.substring(0, i); if(isPalindrome(prefix)){ String target = reverse(s.substring(i)); if(dict.contains(target)) System.out.println(target + " " + s); } } //scan backward for(int i = s.length() - 1; i >= 0; i--){ String suffix = s.substring(i); if(isPalindrome(suffix)){ String target = reverse(s.substring(0, i)); if(dict.contains(target)) System.out.println(s + " " + target); } } } //check if s is a parlindrome public boolean isPalindrome(String s){ for(int i = 0, j = s.length() - 1; i < j; i++, j--){ if(s.charAt(i) != s.charAt(j)) return false; } return true; } //reverse a given string public String reverse(String s){ StringBuilder builder = new StringBuilder(); for(int i = s.length() - 1; i >= 0; i--) builder.append(s.charAt(i)); return builder.toString(); } } }