Palindrome Partitioning II

本文探讨了如何找到将字符串分割成回文子串所需的最少分割次数,并提供了两种算法实现:自顶向下的深度优先搜索和自底向上的动态规划。通过这两种方法有效地解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

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.

For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

第一想法就是dfs,这样写会超时:

public class Solution {
    Map<String,Integer> map=new HashMap<String,Integer>();
        
    public int minCut(String s) {
        int min=Integer.MAX_VALUE;
        if(isPalindrome(s))
            return 0;
        for(int i=0;i<s.length()-1;i++){
            String substr=s.substring(0,i+1);
            if(set.contains(substr)){
                int cutnum=minCut(s.substring(i+1));
                min=cutnum+1<min?cutnum+1:min;
            }else{
                if(isPalindrome(substr)){
                    set.add(substr);
                    int cutnum=minCut(s.substring(i+1));
                    min=cutnum+1<min?cutnum+1:min;
                }else{
                    int cutnum=minCut(s.substring(0,i+1))+minCut(s.substring(i+1,s.length()))+1;
                    min=cutnum+1<min?cutnum+1:min;
                }
            }
        }
        return min;
    }
}
后来我加了备忘录,然后想想这里每次调用substring函数很浪费时间,于是我换成了char[],速度快了很多,但还是超时了,WTF!

public class Solution {
    Map<String,Integer> map=new HashMap<String,Integer>();
    
    public int minCut(String s) {
        return getMinCut(s.toCharArray(), 0,s.length()-1);
    }
	
	public int getMinCut(char[] chars,int left,int right){
		String str=new String(chars, left, chars.length-left);
		if(map.containsKey(str))
			return map.get(str);
		if(isPalindrome(chars,left,right))
        	return 0;
		int min=Integer.MAX_VALUE;
		for(int i=left;i<right;i++){
        	String substr=new String(chars, left, i-left+1);
        	if(map.containsKey(substr)){
        		int leftCut=map.get(substr);
        		int rightCut=getMinCut(chars,i+1,right);
        		min=leftCut+rightCut+1<min?leftCut+rightCut+1:min;
        	}else{
        		if(isPalindrome(chars,left,i)){
        			map.put(substr,0);
        			int rightCut=getMinCut(chars,i+1,right);
            		min=rightCut+1<min?rightCut+1:min;
        		}else{
        			int leftCut=getMinCut(chars,left,i);//这个地方写成了i+1
        			int rightCut=getMinCut(chars,i+1,right);
        			min=leftCut+rightCut+1<min?leftCut+rightCut+1:min;
        		}
        	}
        }
		map.put(str, min);
        return min;
	}
	
	private boolean isPalindrome(char[] chars,int left,int right){
		while(left<right){
			if(chars[left]==chars[right]){
				left++;right--;
			}else{
				return false;
			}
		}
		return true;
	}
}
这个题正确的自上而下的dfp算法:

这里在判断是否是回文数的时候直接在panMap中查找。

public class Solution {
    int[][] panMap;
    int[] map;

    public int minCut(String s) {
        panMap = new int[s.length()][s.length()];
        map = new int[s.length() + 1];
        Arrays.fill(map, Integer.MAX_VALUE);
        map[s.length()] = 0;
        return minCut(s, 0) - 1;
    }

    private int minCut(String s, int start) {
        if (map[start] != Integer.MAX_VALUE) return map[start];
        for (int i = start; i < s.length(); i++) {
            //这里当start==i时肯定会执行
            if (isPan(s, start, i)) {
                map[start] = Math.min(map[start], 1 + minCut(s, i + 1));
            }
        }
        return map[start];
    }

    private boolean isPan(String s, int start, int end) {
        if (start == end) return true;
        if (end == start - 1 && s.charAt(start) == s.charAt(end)) return true;
        if (panMap[start][end] != 0) return panMap[start][end] == 1 ? true : false;
        if (s.charAt(start) == s.charAt(end)) {
            panMap[start][end] = isPan(s, start + 1, end - 1) ? 1 : -1;
        }
        return panMap[start][end] == 1 ? true : false;
    }
}

自下而上的dp算法:

This can be solved by two points:

  1. cut[i] is the minimum of cut[j - 1] + 1 (j <= i), if[j, i] is palindrome.
  2. If [j, i] is palindrome, [j + 1, i - 1] is palindrome, andc[j] == c[i].

public class Solution {
    public int minCut(String s) {
        char[] c = s.toCharArray();
        int n = c.length;
        int[] cut = new int[n];
        boolean[][] pal = new boolean[n][n];
    
        for(int i = 0; i < n; i++) {
            //这里给min赋初始值
            int min = i;
            for(int j = 0; j <= i; j++) {
                if(c[j] == c[i] && (j + 1 > i - 1 || pal[j + 1][i - 1])) {
                    pal[j][i] = true;  
                    min = j == 0 ? 0 : Math.min(min, cut[j - 1] + 1);
                }
            }
            cut[i] = min;
        }
        return cut[n - 1];
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值