java数据结构与算法之求所有子数组问题

  • 求数组子数组的题目是很多类似题目的基础,所以一定要明白如何求一个数组的【所有子数组】
  • 注意:这里讨论的是求数组的【所有子数组】和下面的求数组的【所有连续子数组】问题区分开

①、题目描述

  • 给你一个整数数组nums,求该数组的所有子数组
  • 比如:nums = [1,2,3]
  • 返回,[ [1,2,3], [1,2], [1,3], [1], [2], [3], [2,3], [] ]

②、类似题目

③、代码

  • 核心就是使用递归去做决策,对于数组中的每个位置都可以选择【要或者不要】
  • 如果要当前位置的数,那么继续递归决策他的下一个位置
  • 如果不要当前位置的数,那么继续递归决策他的下一个位置
  • 当决策完数组中最后一个位置时,开始收集前面做好的决策结果(每次收集便得到一个子数组)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xPtpLf06-1647590976752)(picture/子数组问题.png)]

/**
 * 给你一个数组nums,求该数组的子数组集合
 *
 * @param nums 数组
 * @return List 子数组集合
 */
public static List<List<Integer>> subArrayList(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    if (nums == null || nums.length < 1) {
        return list;
    }
    // 递归决策
    process(nums, 0, new ArrayList<>(), list);
    return list;
}

/**
 * 求这种问题,对于每个位置都有两种选择,要或者不要
 *
 * @param nums           数组
 * @param index          当前来到的位置
 * @param decisionResult 每一个位置的决策结果存放集合
 * @param resultList     最终结果集
 */
public static void process(int[] nums, int index, List<Integer> decisionResult, List<List<Integer>> resultList) {
    // 决策完数组最后一个位置后,将结果记录到resultList
    if (nums.length == index) {
        // 注意:Java中list是引用类型,所以这里需要将决策完的结果【拷贝一份】然后放入结果集
        List<Integer> copy = new ArrayList<>(decisionResult);
        resultList.add(copy);
        return;
    }

    // 对于每个位置都有两种选择,要或者不要,定了index位置后,然后去决策index + 1 位置
    // 1、要当前位置的数
    decisionResult.add(nums[index]);
    process(nums, index + 1, decisionResult, resultList);

    // 2、不要当前位置的数(这里注意要把上面add的数remove掉,注意这里是按照数组下标remove的)
    // 注意这里始终是remove的最后一个元素
    decisionResult.remove(decisionResult.size() - 1);
    process(nums, index + 1, decisionResult, resultList);
}

④、题目进阶

统计按位或能得到最大值的子集数目

  • 给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目
  • 如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,则认为数组 a 是数组 b 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同 。
  • 对数组 a 执行 按位或 ,结果等于 a[0] OR a[1] OR … OR a[a.length - 1](下标从 0 开始)。
class Solution {
		// 最大值
    int max = -1;
  	// 出现次数
    int count = 0;

    // 暴力递归解法(也就是求所有子集,对于每个位置都可以选择要或者不要)
    public int countMaxOrSubsets(int[] nums) {
        process(nums,0,0);
        return count;
    }

    /*
     * 递归求得每一个子集,对于每一个位置都可以选择要或者不要
     *
     * @param nums 数组
     * @param index 当前来到的位置
     * @param orRes 异或的结果
     */
    public void process(int[] nums,int index, int orRes){
        if(index >= nums.length){
            // 结算,只记录最大值以及他的次数
            if(orRes > max){
                // orRes大于当前的max,那么说明新发现了比之前的max还要大的数,就将count重置为1
                max = orRes;
                count = 1;
            }else if(orRes == max){
                // orRes等于当前的max,那么就把count++
                count++;
            }
            // orRes小于当前的max,那么就什么也不做
            return;
        }
        // 要当前位置
        process(nums,index + 1,orRes | nums[index]);
        // 不要当前位置
        process(nums,index + 1,orRes);
    }
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值