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

Posted 程序员超时空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
    
    

以上是关于java数据结构与算法之求所有子数组问题的主要内容,如果未能解决你的问题,请参考以下文章

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

数组问题之求最大子数组问题

java数据结构与算法之求树的最大宽度

数据结构与算法面试题子数组的最大和

java数据结构与算法之连续子数组问题

java数据结构与算法之连续子数组问题