LeetCode 777, 698

118 阅读2分钟

LeetCode 777

链接:leetcode.com/problems/sw…

方法:双指针

时间复杂度:O(n) 想法:这题有点头脑风暴的感觉,说到算法倒是也没什么经典算法。还是靠观察题目的特殊性质,所以说start字符串里面的'L'可以穿越所有'X'往左移,'R'可以穿越所有'X'往右移。所以start可以转化成end的充要条件就是,1) start跟end里面的'L'和'R'相对顺序相同。2) 个数相同。3) start里面的'L'必须在end相对应的'L'的同位置或右边,'R'必须在end相对应的'R'的同位置或左边。所以直接两个指针分别指start和end,然后如果是'X'就一直往后挪,抓到不是'X'的地方来比一下。 代码:

class Solution {
    public boolean canTransform(String start, String end) {
        int n = start.length(), i = 0, j = 0;
        
        while (i < n && j < n) {
            while (i < n && start.charAt(i) == 'X') i++;
            while (j < n && end.charAt(j) == 'X') j++;
            if (i < n && j < n) {
                if (start.charAt(i) != end.charAt(j)) {
                    return false;
                }
                if ((start.charAt(i) == 'L' && i < j) || (start.charAt(i) == 'R' && i > j)) {
                    return false;
                }
            }
            else {
                break;
            }
            i++;
            j++;
        }
        
        while (i < n) {
            if (start.charAt(i) != 'X') return false;
            i++;
        }
        while (j < n) {
            if (end.charAt(j) != 'X') return false;
            j++;
        }
        
        return true;
    }
}

LeetCode 698

链接:leetcode.com/problems/pa…

方法:DFS

时间复杂度:O(n!) 想法:这个题写DFS还是应该说是比较好写的,这个题值得讨论的其实就两点。

  1. 为什么不能写背包DP? 如果是问能不能分成两个equal sum subsets,那是可以用背包DP的,但是这个题是k个,就算用背包DP算出来可以达到sum/k,那也并没有多少用,一是背包DP不存储具体的存放方案,二是只达到了一个sum/k不够,没法论证其他的值可以等分成k-1份,而且做这样一次DP,问题变成“剩下的值等分成k-1份”,它没有比原问题简单多少,而做一次DP代价却不小,因此不这样做。
  2. 针对每一个target = sum / k做DFS的时候,需要注意什么? 正如常规的DFS,我们肯定会开一个visited数组,但这里是这样,对每一个target = sum / k做DFS的时候,我们还需要一个index,表示我们目前扫描到哪了,不能每次都从0开始。这个地方就像是不考虑visited这个数组,我们做组合型DFS的时候的做法。 代码:
class Solution {
    public boolean canPartitionKSubsets(int[] nums, int k) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        
        if (sum % k != 0) {
            return false;
        }
        
        boolean[] visited = new boolean[nums.length];
        
        return dfs(nums, k, 0, sum / k, visited, 0);
    }
    
    private boolean dfs(int[] nums, int k, int cur, int target, boolean[] visited, int index) {
        if (k == 1) {
            return true;
        }
        if (cur == target) {
            return dfs(nums, k - 1, 0, target, visited, 0);
        }
        
        for (int i = index; i < nums.length; i++) {
            if (!visited[i] && nums[i] + cur <= target) {
                visited[i] = true;
                if (dfs(nums, k, cur + nums[i], target, visited, i + 1)) {
                    return true;
                }
                visited[i] = false;
            }
        }
        
        return false;
    }
}