字符串回溯算法题模板

这个模板适用于给出一个字符串,然后从字符串中判断其子字符串是否满足某一性质。
比如:
93. 复原IP地址
题目给出一个字符串,需要求出所有可能的 IP 地址格式。
131. 分割回文串
题目给出一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
306.累加数
累加数是一个字符串,组成它的数字可以形成累加序列。一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。

这个模板如下:

Class Solution{
	//res用来保存最后结果
	List res = new ArrayList<>();
	//递归函数,list用于保存满足条件的结果,pos用于指示字符的位置,input为输入的字符串
	public void helper(List list,int pos,String input){
		//当遍历到最后一个字符时,加入结果集
		if(pos == intput.length() && 其它的终止条件){
			res.add(new ArrayList<>(list));
			return;
		}
		for(int i = 1;i <= 子字符需要的长度;i++){
			//剪枝
			if (pos+ i > s.length()) break;
			//获得子字符串
			String subStr = input.subString(pos,pos+i);
			//根据题目要求筛选子字符串
			子字符串筛选....
			//将符合条件的子字符串加入list
			list.add(subStr);
			helper(list,pos+1,input);
			//回退
			list.remove(list.size()-1);
		}
	}
}

93. 复原IP地址

/**
 * ip地址每段在0~255之间,且不能以0作为开头,如012,这些可以作为剪枝条件
 * 因为每次分割出的自字符串需要用.拼接,所以暂时使用List来储存分段的ip地址,最后再用.拼接即可
 */
class Solution {
    List res = new ArrayList<>();

    public List restoreIpAddresses(String s) {
        if (s.isEmpty()) return res;
        helper(s, 0, new ArrayList());
        return res;
    }

    //pos表示当前分割的字符串位置
    private void helper(String s, int cur, List list) {
        if (list.size() >= 4) {
            if(cur == s.length()) res.add(String.join(".", list));
            return;
        }

        for (int i = 1; i <= 3; i++) {
            if (cur + i > s.length()) break;
            String subStr = s.substring(cur, cur + i);
            //判断ip地址是否合适
            if ((subStr.startsWith("0") && subStr.length() > 1) || (i == 3 && Integer.valueOf(subStr) > 255))
                continue;
            list.add(subStr);
            helper(s, cur + i, list);
            list.remove(list.size() - 1);
        }
    }
}

131. 分割回文串

/**
 * 使用回溯算法。
 * 只有一个字符的字符串也是回文串
 * 所以设定一个变量cur指代当前递归的字符串位置,如果当前字符是回文串,则加入结果集,如果不是直接continue。
 * 当cur==s.length()时表示已找到一个结果,加入结果集
 */
class Solution {
    List> res = new ArrayList<>();

    public List> partition(String s) {
        if (s.isEmpty()) return res;
        helper(s, new ArrayList<>(), 0);
        return res;
    }

    private void helper(String s, List list, int cur) {
        if (cur == s.length()) {
            res.add(new ArrayList<>(list));
            return;
        }
        for (int i = 1; i <= s.length(); i++) {
            if (cur + i > s.length()) break;
            String subStr = s.substring(cur, cur + i);
            if (!isPalindrome(subStr)) continue;
            //加入当前回文串
            list.add(subStr);
            helper(s, list, cur + i);
            //回退
            list.remove(list.size() - 1);
        }
    }

    private boolean isPalindrome(String subStr) {
        if (subStr.length() == 1) return true;
        char[] chars = subStr.toCharArray();
        for (int i = 0; i < chars.length / 2; i++) {
            if (chars[i] != chars[chars.length - i - 1])
                return false;
        }
        return true;
    }
}

306. 累加数

class Solution {
    boolean flag = false;

    public boolean isAdditiveNumber(String num) {
        if (num.isEmpty()) return false;
        helper(num, 0, new ArrayList<>());
        return flag;
    }

    private void helper(String num, int cur, List list) {
        //判断
        if (cur == num.length() && list.size() > 2) {
            flag = true;
            return;
        }
        for (int i = 1; i <= num.length(); i++) {
            if (flag) break;
            if (cur + i > num.length()) break;
            String subStr = num.substring(cur, cur + i);
            //当前数不能以0开头
            if (subStr.startsWith("0") && subStr.length() > 1) continue;
            //如果结果集已经有两个数,则判断前两个数相加是否为当前数
            if (list.size() >= 2) {
                if (Long.valueOf(subStr) != Long.valueOf(list.get(list.size() - 1)) + Long.valueOf(list.get(list.size() - 2)))
                    continue;
            }
            list.add(subStr);
            helper(num, cur + i, list);
            list.remove(list.size() - 1);
        }
    }
}

842. 将数组拆分成斐波那契序列

给定一个数字字符串 S,比如 S = “123456579”,我们可以将它分成斐波那契式的序列 [123, 456, 579]。
形式上,斐波那契式序列是一个非负整数列表 F,且满足:
0 <= F[i] <= 2^31 - 1,(也就是说,每个整数都符合 32 位有符号整数类型);
F.length >= 3;
对于所有的0 <= i < F.length - 2,都有 F[i] + F[i+1] = F[i+2] 成立。
另外,请注意,将字符串拆分成小块时,每个块的数字一定不要以零开头,除非这个块是数字 0 本身。

class Solution {
    public List splitIntoFibonacci(String S) {
        List res = new ArrayList<>();
        helper(S, res, 0);
        return res;
    }

    private boolean helper(String s, List list, int pos) {
        //因为斐波拉契数组至少为3个元素,找到后直接返回true
        if(pos == s.length() && list.size() > 2){
            return true;
        }
        for (int i = 1; i <= s.length(); i++) {
            if (pos + i > s.length()) break;
            String subStr = s.substring(pos, pos + i);
//剪枝条件1:数字以0开头
            if (subStr.startsWith("0") && subStr.length() > 1) continue;
            //剪枝条件2:当前字符串不能超过Integer的最大值
            if (Long.valueOf(subStr) > Integer.MAX_VALUE) break;
            //剪枝条件3:当前数不等于前两个数之和
            if (list.size() >= 2 && Integer.valueOf(subStr) != list.get(list.size() - 1) + list.get(list.size() - 2))
                continue;
            //将当前值加入结果集
            list.add(Integer.valueOf(subStr));
            //递归,找到一个结果就返回
            if (helper(s, list, pos + i)) return true;
            list.remove(list.size() - 1);
        }
        return false;
    }
}

你可能感兴趣的:(LeetCode)