leetcode6

17.给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:

输入:digits = ""
输出:[]
示例 3:

输入:digits = "2"
输出:["a","b","c"]
 

提示:

0 <= digits.length <= 4
digits[i] 是范围 ['2', '9'] 的一个数字。

class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> tab=new ArrayList<>();
        if(digits.length()==0){
            return tab;
        }
        //建立哈希表存储
        Map<Character,String> hashMap=new HashMap<>();
        hashMap.put('2',"abc");
        hashMap.put('3',"def");
        hashMap.put('4',"ghi");
        hashMap.put('5',"jkl");
        hashMap.put('6',"mno");
        hashMap.put('7',"pqrs");
        hashMap.put('8',"tuv");
        hashMap.put('9',"wxyz");
        //回溯一下呢?
        func(tab,digits,hashMap,0,new StringBuilder());
        return tab;
    }
    //n标识从第几个字符开始,sb用于拼接
    public void func(List<String> tab,String digits,Map<Character,String> map,int n,StringBuilder sb){
        //第n个字符的映射,如果够长了,就添加到列表中
        if(n==digits.length()){
            tab.add(sb.toString());
        }else{
            //否则就添加
            char c=digits.charAt(n);
            //找到这个字符对应的字符串
            String s=map.get(c);
            int length=s.length();
            for(int i=0;i<length;i++){
                sb.append(s.charAt(i));
                func(tab,digits,map,n+1,sb);
                //回溯,比如23,现在sb里有个a,然后调用func sb变成ad,这个时候满足长度,添加到tab,
                //然后这个调用结束,再删除d,然后sb里还是a,sb变成ae,这个时候满足长度,添加到tab,
                //然后这个调用结束,再删除e,然后sb里还是a,sb变成af,这个时候满足长度,添加到tab,
                //然后这个调用结束,再删除f,小for循环也结束,走到大for循环,直至回溯完成。
                sb.deleteCharAt(n);
            }
        }
    }
}

 22.数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:

输入:n = 1
输出:["()"]
 

提示:

1 <= n <= 8

class Solution {
    public List<String> generateParenthesis(int n) {
        //也是一个回溯题
        List<String> res=new ArrayList<>();
        func(res,n,0,0,new StringBuilder());
        return res;
    }
    public void func(List<String> res,int n,int indexLeft,int indexRight,StringBuilder sb){
        //如果左括号和右括号都达到n个,就加入列表
        if(sb.length()==2*n){
            res.add(sb.toString());
            return;
        }
        if(indexLeft<n){
            sb.append("(");
            func(res,n,indexLeft+1,indexRight,sb);
            sb.deleteCharAt(sb.length()-1);
        }
        if(indexRight<indexLeft){
            sb.append(")");
            func(res,n,indexLeft,indexRight+1,sb);
            sb.deleteCharAt(sb.length()-1);
        }
    }
}

32.给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例 1:

输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:

输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
示例 3:

输入:s = ""
输出:0
 

提示:

0 <= s.length <= 3 * 104
s[i] 为 '(' 或 ')'

 

 1.一些令人窒息的动态规划

class Solution {
    public int longestValidParentheses(String s) {
        //动态规划是什么,我是谁
        int n=s.length();
        int max=0;
        if(n==0){
            return 0;
        }
        int[] res=new int[n];
        for(int i=1;i<n;i++){
            if(s.charAt(i)==')'){
                if(s.charAt(i-1)=='('){
                    //如果一开局就来了一对,必须初始化为2,因为-2越界
                    if(i<2){
                        res[i]+=2;
                    }else{
                        res[i]=res[i-2]+2;
                    }
                }else{
                    //前一个右括号对称的点的前一个的结果和前一个右括号的结果再加2,相当于不仅考虑了里面的,还考虑了外面的。
                    //如果对称的点不再列表内,就直接里面加2,否则还要算上外面的。
                    if(i-1-res[i-1]>=0&&s.charAt(i-1-res[i-1])=='('){
                        if(i-2-res[i-1]>=0){
                            res[i]=res[i-1-res[i-1]-1]+2+res[i-1];
                        }else{
                            res[i]=2+res[i-1];
                        }
                    }
                }
            }  
            max=Math.max(res[i],max);
        }
        return max;
    }
}

2.栈

class Solution {
    public int longestValidParentheses(String s) {
        //栈应该比较好搞
        Stack<Integer> stack=new Stack<>();
        //如果是左括号,直接压i,是右括号,弹出,弹完为空则压栈就是没匹配到的右括号,不为空说明匹配到了,结果是当前下标减栈顶。
        //如果栈为空,说明当前的右括号为没有被匹配的右括号,我们将其下标放入栈中来更新我们之前提到的「最后一个没有被匹配的右括号的下标」
        //如果栈不为空,当前右括号的下标减去栈顶元素即为「以该右括号为结尾的最长有效括号的长度」
        int n=s.length();
        if(n==0){return 0;}
        int max=0;
        stack.push(-1);
        for(int i=0;i<n;i++){
           if(s.charAt(i)=='('){
               stack.push(i);
           }else{
               stack.pop();
               if(stack.isEmpty()){
                   stack.push(i);
               }else{
                   max=Math.max(max,i-stack.peek());
               }
           }
        }
        return max;
    }
}

其实这个题目第一想法就是双指针,但是没有考虑周全。

class Solution {
    public int longestValidParentheses(String s) {
        //有点像接雨水的意思了
        int n=s.length();
        if(n==0){return 0;}
        int left=0;
        int right=0;
        int max1=0;
        int max2=0;
        for(int i=0;i<n;i++){
            if(s.charAt(i)=='('){
                left++;
            }else{
                right++;
            }
            if(left==right){
                max1=Math.max(max1,left*2);
            }else if(right>left){
                left=0;
                right=0;
            }
        }
        left=0;
        right=0;
        for(int i=n-1;i>=0;i--){
            if(s.charAt(i)=='('){
                left++;
            }else{
                right++;
            }
            if(left==right){
                max2=Math.max(max2,left*2);
            }else if(left>right){
                left=0;
                right=0;
            }
        }
        return Math.max(max1,max2);
    }
}

34.给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
 

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:

输入:nums = [], target = 0
输出:[-1,-1]
 

提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109

考的二分法都是细节拉满,吐了!!!

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res=new int[]{-1,-1};
        int l=binarySearch(nums,target,true);
        //???为什么减1,因为false找的是大于目标的第一个,所以后面还要满足r的值为target,如果不满足意味着压根没有目标值。
        int r=binarySearch(nums,target,false)-1;
        //为什么要写个这个条件???
        if(l<=r&&r<nums.length&&nums[l]==target&&nums[r]==target){
            res[0]=l;
            res[1]=r;
        }
        return res;
    }
    public int binarySearch(int[] nums,int target,boolean flag){
        //找最小值
        int left=0;
        int right=nums.length-1;
        int temp;
        //???为什么是这么多,只要不在范围内?为什么-1不行
        int res=nums.length;
        while(left<=right){
            temp=(left+right)/2;
            //false找大于目标的第一个,true找大于等于目标的第一个
            if(nums[temp]>target||(flag&&nums[temp]>=target)){
                res=temp;
                right=temp-1;
            }else{
                left=temp+1;
            }
        }
        return res;
    }
}

39.给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:

输入: candidates = [2], target = 1
输出: []
 

提示:

1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都 互不相同
1 <= target <= 500

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res=new ArrayList<>();
        List<Integer> temp=new ArrayList<>();
        func(res,candidates,target,temp,0);
        return res;
    }
    //感觉可以回溯一下
    public void func(List<List<Integer>> res,int[] candidates,int target,List<Integer> temp,int index){
        int n=candidates.length;
        //走完了整个组合,结束
        if(index==n){
            return;
        }
        //如果此时目标已经减到0,就可以加进去返回了
        if(target==0){
            res.add(new ArrayList<>(temp));
            return;
        }
        //往下走
        func(res,candidates,target,temp,index+1);
        if(target-candidates[index]>=0){
            //继续走
            temp.add(candidates[index]);
            func(res,candidates,target-candidates[index],temp,index);
            //回溯
            temp.remove(temp.size()-1);
        }
    }
}

62.一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

示例 1:


输入:m = 3, n = 7
输出:28
示例 2:

输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下
示例 3:

输入:m = 7, n = 3
输出:28
示例 4:

输入:m = 3, n = 3
输出:6
 

提示:

1 <= m, n <= 100
题目数据保证答案小于等于 2 * 109

递归肯定是可以的qwq

class Solution {
    public int uniquePaths(int m, int n) {
        //思路:递归可以,如果第一排的话只可能是右移来,第一列是下移;其他都有两种可能。
        if(m==1){
            return 1;
        }
        if(n==1){
            return 1;
        }
        return uniquePaths(m-1,n)+uniquePaths(m,n-1);
    }
}

 一个经典的超时出现了!好耶!

那么动态规划一下:

class Solution {
    public int uniquePaths(int m, int n) {
        //动态规划打表了
        int[][] res=new int[m][n];
        for(int i=0;i<n;i++){
            res[0][i]=1;
        }
        for(int j=0;j<m;j++){
            res[j][0]=1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                res[i][j]=res[i-1][j]+res[i][j-1];
            }
        }
        return res[m-1][n-1];
    }
}

 笑死,排列组合还给高中老师了。

class Solution {
    public int uniquePaths(int m, int n) {
        long ans=1;
        for(int x=m,y=1;y<n;y++,x++){
            ans=ans*x/y;
        }
        return (int)ans;
    }
}

55.给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
 

提示:

1 <= nums.length <= 3 * 104
0 <= nums[i] <= 105

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 记录当前能达到的最远路径,只要大于等于数组最后一个值的下标即可。

注意:要判断当前i是否能达到!!!

class Solution {
    public boolean canJump(int[] nums) {
        int n=nums.length;
        int max=0;
        if(n==1){
            return true;
        }
        for(int i=0;i<n-1;i++){
            //要判断当前的i是否是能到达的地方!!!
            if(i<=max){
                max=Math.max(max,i+nums[i]);
                if(max>=n-1){
                    return true;
                }
            }
        }
        return false;
    }
}

105.给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:


输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]
 

提示:

1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均 无重复 元素
inorder 均出现在 preorder
preorder 保证 为二叉树的前序遍历序列
inorder 保证 为二叉树的中序遍历序列

九日集训做过的题,浅写一个递归.注意使用哈希表减少遍历

class Solution {
    Map<Integer,Integer> hashMap=new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //做一个哈希表快速找根节点,以防每次都遍历
        int n=preorder.length;
        for(int i=0;i<n;i++){
            hashMap.put(inorder[i],i);
        }
        return func(preorder,inorder,0,n-1,0,n-1);   
    }
    //做一个递归函数
    public TreeNode func(int[] preorder,int[] inorder,int pl,int pr,int il,int ir){
        //退出递归的条件
        if(pl>pr){
            return null;
        }
        //先找到中序遍历中根节点的位置
        int preroot=pl;
        int inroot=hashMap.get(preorder[preroot]);
        int leftlength=inroot-il;
        int rightLength=ir-inroot;
        TreeNode root=new TreeNode(preorder[preroot]);
        root.left=func(preorder,inorder,pl+1,pl+leftlength,il,inroot-1);
        root.right=func(preorder,inorder,pl+leftlength+1,pr,inroot+1,ir);
        return root;
    }    
}

迭代真的就是儿子论

128.给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:

输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
 

提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109

判断这个数的前一个数没有!!! 

class Solution {
    public int longestConsecutive(int[] nums) {
        //快乐哈希
        int n=nums.length;
        if(n==0){
            return 0;
        }
        Set<Integer> hashSet=new HashSet<>();       
        for(int i=0;i<n;i++){
            hashSet.add(nums[i]);
        }
        //遍历
        int maxLength=1;
        //hashSet可以直接foreach遍历
        for(int i:hashSet){
            //这个判断就是核心!!
            if(!hashSet.contains(i-1)){
                //从连续的入口开始
                int k=1;
                int num=i;
                while(hashSet.contains(num+1)){
                    num++;
                    k++;
                }
                maxLength=Math.max(k,maxLength);
            }
        }
        return maxLength;
    }
}

560.给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

示例 1:

输入:nums = [1,1,1], k = 2
输出:2
示例 2:

输入:nums = [1,2,3], k = 3
输出:2
 

提示:

1 <= nums.length <= 2 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107 

笑死,子数组的概念是原数组连续元素构成的数组。 

暴力遍历居然没超时,crazy!!

class Solution {
    public int subarraySum(int[] nums, int k) {
        //先搞出个枚举来
        int length=nums.length;
        if(length==1){
            if(nums[0]==k){
                return 1;
            }else{
                return 0;
            }
        }
        int res=0;
        int temp=0;
        for(int i=0;i<length;i++){
            temp=nums[i];
            if(temp==k){
                res++;
            }
            int j=i+1;
            while(j<length){
                temp+=nums[j];
                j++;
                if(temp==k){
                    res++;
                }
            }
        }
        return res;
    }
}

 哈希一下

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer,Integer> hashMap=new HashMap<>();
        int res=0;
        int count=0;
        //为什么呢,防止漏掉前面几个,比如说第一个就是k,如果不加(0,1)就会被漏掉。
        hashMap.put(0,1);
        for(int num:nums){
            count+=num;
            if(hashMap.containsKey(count-k)){
                res+=hashMap.get(count-k);
            }
            //如果已经有这个数,这个数的急促上再加1
            hashMap.put(count,hashMap.getOrDefault(count,0)+1);
        }
        return res;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值