【code基础】剪枝操作

剪枝操作可以去除重复无意义的操作,从而提升时间复杂度和空间复杂度
剪枝的常见思路:

  • 排序和去重,这里常见Arrays.sort(nums) HashSet<>()
  • 提前结束循环或者跳出循环

以力扣上的2344题为例: https://leetcode.cn/problems/minimum-deletions-to-make-array-divisible/
给你两个正整数数组 nums 和 numsDivide 。你可以从 nums 中删除任意数目的元素。
请你返回使 nums 中 最小 元素可以整除 numsDivide 中所有元素的 最少 删除次数。如果无法得到这样的元素,返回 -1 。
如果 y % x == 0 ,那么我们说整数 x 整除 y 。

输入:nums = [2,3,2,4,3], numsDivide = [9,6,9,3,15]
输出:2
解释:
[2,3,2,4,3] 中最小元素是 2 ,它无法整除 numsDivide 中所有元素。
我们从 nums 中删除 2 个大小为 2 的元素,得到 nums = [3,4,3] 。
[3,4,3] 中最小元素为 3 ,它可以整除 numsDivide 中所有元素。
可以证明 2 是最少删除次数。

输入:nums = [4,3,6], numsDivide = [8,2,6,10]
输出:-1
解释:
我们想 nums 中的最小元素可以整除 numsDivide 中的所有元素。
没有任何办法可以达到这一目的。


总结思路:其实是求numsDivide 的最小公约数

  • 对nums数组进行排序,最小公约数,那就是从小到大
  • numsDivide数组中可能会出现重复元素,如果使用暴力遍历,会产生时间的浪费,这里先去重,并且取最小值,为nums数组遍历的上限(超过该最小值也不是最小公约数)
  • nums数组中也存在重复的元素,这里使用set集合,如果是重复元素进行拦截,计数器直接+1,就不进入复杂的计算过程了
 //超出时间限制,增加剪枝操作
public int minOperations(int[] nums, int[] numsDivide) {

    //1.对numsDivide做剪枝操作,使用TreeSet进行排序
    TreeSet<Integer> set = new TreeSet<>();
    for (int i = 0; i < numsDivide.length; i++) {
        set.add(numsDivide[i]);
    }
    int min = set.first();

    //2.因为要对nums数组统计删除的个数,所以这里是对nums数组的遍历,
    // 增加了排序,剪枝 nums[i] <= min以及使用HashSet去重
    Arrays.sort(nums);
    HashSet<Integer> s = new HashSet<>();
    for (int i = 0; i<nums.length && nums[i] <= min;) {
        if (!s.add(nums[i])) i++;
        else if (canDivide(nums[i],set)) return i;
        else i++;

    }
     return -1;
}

public boolean canDivide(int num,TreeSet<Integer> set){
    Iterator<Integer> iterator = set.iterator();
    while (iterator.hasNext()){
        if ((iterator.next())%num !=0) return false;
    }
    return true;
}
posted @ 2022-09-27 17:31  xiaoyu_jane  阅读(33)  评论(0编辑  收藏  举报