剑指34.二叉树中和为某一值路径38.字符串排列39.数组出现次数超过一半数字42.连续子数组最大和(ArrayList,HashSet,Hashmap)

剑指offer34

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

在这里插入图片描述

  1. list容器(数组线性表):List<List<Integer>> list=new ArrayList<>()
  • list.add(obj)向尾部添加元素,list.add(int index,Object obj)向index索引位置添加元素。特别要注意的是,add()方法加入的是对象的地址,要加入不同对象需要new新的对象。add()允许添加重复元素。
  • list.remove(int i)删除索引i位置的元素,可以这样子写remove(list.indexOf(Object a))。另一种是remove(Object a),如果是对象引用则直接传对象引用作为参数,若传的是基本类型,则需要先转化成包装类remove(Integer.valueOf(250))
  • list.size()获取list的长度
  • list.get(int i)返回索引下标为i的元素
  • list.contains(int i)容器中含有i则返回true,可以用来去重
  • List list=new ArrayList<>(Arrays.asList(object a,object b,object c…)):一种初始化写法
  1. 注意找到正确的路径记录进list时,若直接执行list.add(path) ,则是将 path 对象加入了list ;后续 path 改变时,list 中的 path 对象也会随之改变。因此每次添加一个新的容器进入到容器,都要新实例化一个新的容器。list.add(new ArrayList<>(path)),相当于复制了一个path加入到list。

  2. 深搜过程中,如果是叶子结点则判断当前路径能不能加入到list当中然后退出当前搜索,否则继续遍历左子树和右子树。难点在于路径记录,path记录时如何保证当前父节点路径不变而只改变后加入的子节点路径。令每个结点进入搜索时当前val值加入到path,退出搜索回溯父节点前,再从path中退出来

    public void dfs( List<List<Integer>> list,List<Integer> path,TreeNode root,int target)  //注意整形Integer首字母要大写
        {
            if(root.right==null&&root.left==null)//叶子节点
            {
            if(target==root.val)
            {
                path.add(target);
                list.add(new ArrayList<>(path));
                path.remove(path.size()-1);
                return;
            }
            }       
            path.add(root.val); //先进
            if(root.left!=null) //不用root判空
            dfs(list,path,root.left,target-root.val);
            if(root.right!=null)
            dfs(list,path,root.right,target-root.val);
            path.remove(path.size()-1);  //后退
        }
    }
    

剑指offer38

输入字符串,打印出该字符串中字符的所有排列。你可以以任意顺序返回这个字符串数组,里面不能有重复元素。

输入:s = “abc”
输出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]

  1. String.valueOf(char[] data):将char[]数组转换成String
  2. list.toArray(new String[list.size()])把list容器转化为指定类型的数组
  3. Set容器(不容许有重复元素的集合):HashSet site=new HashSet<>()
  • 方法:add(),remove(String),contains(String)
  1. dfs+回溯。用一个全局的visit数组来记录下使用过的字符 ,回溯前再置为0。 一开始去重用的是!list.contains(String),后面发现超时了。然后又改成HashSet容器来装字符串数组,居然能AC,可能这就是HashSet的魅力吧。减少时间的关键在于剪支,同一个位置(意味着同一个dfs内的循环)如果是先前使用过的字符则可直接continue,所以在每一个dfs都要开辟一个HashSet来记录当前位置使用过的字符。剪枝过后就不需要去重。
class Solution {
    int[] visit=new int[8]; 
    HashSet<String> list=new HashSet<>();
    public String[] permutation(String s){
            char[] temp=new char[s.length()];
            dfs(s,temp,0);                     
            return list.toArray(new String[list.size()]);
    }
    public void dfs(String s,char[] temp,int charindex)
    {
        if(s.length()==charindex)
        {     
            list.add(new String(temp,0,s.length()));              
            return;
        }
        HashSet<Character> v=new HashSet<>(); //真正的剪枝
        for(int i=0;i<s.length();i++)
        {
            if(visit[i]==0&&!v.contains(s.charAt(i)))
            {
                visit[i]=1;
                v.add(s.charAt(i));
                temp[charindex]=s.charAt(i);
                dfs(s,temp,charindex+1);               
                visit[i]=0;
                if(charindex==s.length()-1) //假的剪枝
                return;
            }                       
        }
    }
}

剑指offer39

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

  1. HashMap:HashMap<Integer,Integer> hashmap=new HashMap<>()
  • hashmap.put(i,j):添加元素key=i对应value为j
  • hashmap.get(i):访问i对应的value,若不存在key则返回null,可以在初次插入用来判空
  • for(Integer(key类型) i:hashmap.keySet()) hashmap.get(i)
  • for(Integer(value类型) i:hashmap.values())
  • containsKey()/containsValue() 容器含有对应的key值或者value则返回true,用来判空
  1. 摩尔投票法,前a个数字的票数和为0,则剩余(n-a)个数的票数之和一定仍然>0(题目说明一定存在大于一半数量的数),剩余数组的众数一定不变。vote==0时,当前的num值即为当前这一轮投票区间的众数。

剑指offer42

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6

  1. 动规题,cur记录下以当前索引位置为最右端的最大子数组。cur = Math.max(cur+nums[i],nums[i]);以当前索引位置为右端点的最大子数组中,当前索引位置左边的值之和一定为正数,否则只有它自身。


今日总结

刷题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值