leecode刷题总结

链表:

24. 两两交换链表中的节点

难度中等1048

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:

输入:head = []
输出:[]
示例 3:

输入:head = [1]
输出:[1]

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

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head==null ||head.next==null){
            return head;
        }
        ListNode   res=head;
        while(res!=null &&res.next!=null){
            int temp=res.val;
            res.val=res.next.val;
            res.next.val=temp;
            res=res.next.next;
        }
      return head;
    }
}

234. 回文链表

难度简单1122

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

示例 1:

输入:head = [1,2,2,1]
输出:true

示例 2:

输入:head = [1,2]
输出:false

 思路:将链表中元素值存入数组中,判断数组是否回文就可以了

 class Solution {
    public boolean isPalindrome(ListNode head) {
        List<Integer> vals = new ArrayList<Integer>();
        ListNode currentNode = head;
        while (currentNode != null) {
            vals.add(currentNode.val);
            currentNode = currentNode.next;
        }
        // 使用双指针判断是否回文
        int front = 0;
        int back = vals.size() - 1;
        while (front < back) {
            if (!vals.get(front).equals(vals.get(back))) {
                return false;
            }
            front++;
            back--;
        }
        return true;
    }
}

19. 删除链表的倒数第 N 个结点

难度中等1567

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

进阶:你能尝试使用一趟扫描实现吗?

示例 1:

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

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1] 

思路:定义两个节点,一个fast,一个slow(slow.next=head)先让fast走n步,然后fast和slow同时走,当fast==null停止,slow刚好走到前面那个节点处。这个思路在前面一道题返回链表后面n各元素使用过。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        ListNode fast = head;
        ListNode slow = dummy;
        while(n>0){
            fast=fast.next;
            n--;
        }
        while(fast!=null){
            fast=fast.next;
            slow=slow.next;
        }
      slow.next=slow.next.next;
       ListNode ans = dummy.next;
        return ans;
      
    }
}

括号问题:

20. 有效的括号

难度简单2655

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:输入:s = "(]" 输出:false

示例 4:输入:s = "([)]" 输出:false

示例 5:输入:s = "{[]}" 输出:true

 思路:使用栈实现,但要注意map存入括号的key,value顺序。

因为我们应该看到右括号),},]是来检查栈顶元素是不是对应的左括号,所以我们应该首先将左括号存入,当遇到右括号时看栈顶元素是不是对应的左括号,而且map.get()方法,得到value比较方便。

class Solution {
    public boolean isValid(String s) {
        int len=s.length();
        if(len%2==1)
        return false;
        Map<Character,Character>  map=new HashMap<>();
        map.put(')','(');
        map.put('}','{');
        map.put(']','[');
        Deque<Character>   stack=new LinkedList<>();
        for(int i=0;i<len;i++){
            char c=s.charAt(i);
            if(map.containsKey(c)){
                if(stack.isEmpty() || map.get(c)!=stack.peek()){
                    return  false;
                }
                stack.pop();
            }else{
                stack.push(c);
            }
        }
        return  stack.isEmpty();


    }
}

括号生成 (一道回溯问题)

22. 括号生成

难度中等2053

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

有效括号组合需满足:左括号必须以正确的顺序闭合。

示例 1:

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

示例 2:

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

回溯本质是暴力求解+递归。所以很容易得到递归结束条件,当left和right都为0。(left和right是指可以放多少括号)。

这道题注意递归的执行过程,和剪枝的代码

大概阐述一个过程:

①四次递归字符串变为(((,又三次递归变为((()))。此时程序要结束啦,返回到第三次递归处,字符串变为((,注意而不是变为(((,因为每次字符串修改是在递归中实现的,然后变为(()下一步(()())

②又该结束程序,这是字符串变为了((),然后(())()。下一步结束程序变为(())程序下一步要加),这是进行剪枝了因为left=1,right=0,剪枝后(变为这样,然后()结果为

()(())

③最后一次,程序结束()(是这样的,然后()(),然后()()()结束。

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> res=new LinkedList<>();
        if(n==0){
            return res;
        }
        dfs("",n,n,res);
          return res;
    }
    private void dfs(String x,int left,int right,List<String> res){
        if(left==0 && right==0){
            res.add(new String(x));
            return;
        }
//剪枝
       if(left>right){
           return;
       }
       if(left>0){
           dfs(x+"(",left-1,right,res);
       }
        if(right>0){
           dfs(x+")",left,right-1,res);
       }
    }
}

回溯

78. 子集

难度中等1326

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

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

示例 2:

输入:nums = [0]
输出:[[],[0]]

比较简单,多刷几个回溯题就能看懂了

推荐

全排列,全排列2,子集,子集2,组合,组合2,和括号生产。

看不懂多debug,多想,多画

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res=new LinkedList<>();
        int len=nums.length;
        if(len==0)
        return res;
        Deque<Integer> path=new ArrayDeque<>();
        dfs(nums,len,0,res,path);
        return res;



    }
    private void dfs(int []nums,int len,int begin, List<List<Integer>> res,Deque<Integer> path){
        res.add(new ArrayList<>(path));
        for(int i=begin;i<len;i++){
            path.add(nums[i]);
            dfs(nums,len,i+1,res,path);
            path.removeLast();

        }
    }
}

90. 子集 II

难度中等652

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

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

示例 2:

输入:nums = [0]
输出:[[],[0]]

 避免重复,其实和组合2,全排列2相似。

检测重复的代码确实巧妙,通常的做法是先将数组排序,然后在递归的过程中,当前索引i处元素不能等于索引出i-1的元素,同时也要保证不在同一层

引用了Leecode40. 组合总和 II

题解中某位大佬评论

力扣

解释语句: if cur > begin and candidates[cur-1] == candidates[cur] 是如何避免重复的。



这个避免重复当思想是在是太重要了。
这个方法最重要的作用是,可以让同一层级,不出现相同的元素。即
                  1
                 / \
                2   2  这种情况不会发生 但是却允许了不同层级之间的重复即:
               /     \
              5       5
                例2
                  1
                 /
                2      这种情况确是允许的
               /
              2  
                
为何会有这种神奇的效果呢?
首先 cur-1 == cur 是用于判定当前元素是否和之前元素相同的语句。这个语句就能砍掉例1。
可是问题来了,如果把所有当前与之前一个元素相同的都砍掉,那么例二的情况也会消失。 
因为当第二个2出现的时候,他就和前一个2相同了。
                
那么如何保留例2呢?
那么就用cur > begin 来避免这种情况,你发现例1中的两个2是处在同一个层级上的,
例2的两个2是处在不同层级上的。
在一个for循环中,所有被遍历到的数都是属于一个层级的。我们要让一个层级中,
必须出现且只出现一个2,那么就放过第一个出现重复的2,但不放过后面出现的2。
第一个出现的2的特点就是 cur == begin. 第二个出现的2 特点是cur > begin.

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res=new LinkedList<>();

        int len=nums.length;
        if(len==0)
        return res;
        Arrays.sort(nums);
        Deque<Integer> path=new  ArrayDeque<>();
        dfs(nums,len,0,path,res);
        return res;

    }
    private void dfs(int []nums,int len,int begin, Deque<Integer> path,List<List<Integer>> res){
   
      res.add(new ArrayList<>(path));
        
        for(int i=begin;i<len;i++){
            if(i>begin && nums[i]==nums[i-1]){
            continue;
            }
            path.add(nums[i]);
            dfs(nums,len,i+1,path,res);
            path.removeLast();
            
            
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于LeetCode,我可以提供一些指导和建议。LeetCode是一个非常受欢迎的在线编程平台,提供了大量的编程目,涵盖各种算法和数据结构的知识点。 要有效地LeetCode目,以下是一些建议: 1. 熟悉常见的数据结构和算法:在开始之前,你需要对常见的数据结构(如数组、链表、栈、队列、树等)和算法(如排序、查找、递归、动态规划等)有一定的了解。 2. 顺序:可以按照目的难度或者类型进行。刚开始可以选择一些简单的目,逐渐提升到中等和困难难度的目。另外,可以按照目类型进行分类,比如数组、链表、树等。 3. 目分析:在开始解之前,仔细阅读目,并理解问的要求。可以考虑一些边界情况和特殊情况。 4. 设计合适的解决方案:根据目要求,设计出符合要求的解决方案。可以先在纸上画图或者写伪代码,再实现代码。 5. 编写高质量的代码:编写代码时,注意代码的可读性、可维护性和效率。可以考虑使用适当的数据结构和算法来优化代码。 6. 调试和测试:编写完代码后,进行调试和测试,确保代码能够正确地解决问。 7. 多解法比较:对于一道目,可以尝试不同的解法,比较它们的优劣,并分析其时间复杂度和空间复杂度。 8. 学习他人的解法:在过程中,可以参考他人的解思路和代码,并学习其中的优秀之处。 9. 计划:可以制定一个计划,每天或每周一定数量的目,并坚持下去。 10. 总结和复习:在过程中,及时总结自己的思考和解过程,对于一些常见的算法和技巧进行复习和加深理解。 希望以上的建议对你有所帮助。祝你在LeetCode中取得好成绩!如果你有其他问,也欢迎继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值