栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

leetcode热题100——第三天:15、17、19、20、21

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

leetcode热题100——第三天:15、17、19、20、21

文章目录
    • 1. 15.三数之和
      • 1. 题目描述
      • 2. 题目解析
    • 2. 17.电话号码的字母组合
      • 1.题目描述
      • 2. 题目解析
    • 3. 19.删除链表的倒数第 N 个结点
      • 1.题目描述
      • 2. 题目解析
        • 1. 方法一:获取长度再找到要删除的结点
        • 2. 方法二:栈
        • 3. 方法三:快慢指针
    • 4. 20.有效的括号
      • 1.题目描述
      • 2. 题目解析
    • 5. 21.合并两个有序链表
      • 1. 题目描述
      • 2. 题目解析

1. 15.三数之和

没有复杂度要求就好好解

1. 题目描述

2. 题目解析

首先人来求三个数相加为0,先看小的加大的是不是等于0,小于0则小数替换成较大的,大于0则大数替换成较小的,所以计算机算首先应该排序。

  1. 排序:将数组从小到大进行排序;
  2. 遍历:首先以第一个数为基准,选择后续最小与最大的数,看三者相加是否为0,如果小于0,则替换最小的那个数,选取后面较大的数,如果大于0,最大的数替换掉,选取前面较小的数;直至两个数重合,才把以第一个数为基准的情况找完;
  3. 重复遍历:选取第二个数为基准重复操作,注意:因为答案中不能包括重复的结果,所以如果该数与前一个数值相等,则再往后挪;直至挪到该数大于0为止(因为大于0则三数之和肯定会比0大)。
class Solution {
    public List> threeSum(int[] nums) {
        Arrays.sort(nums);
        List>res=new ArrayList<>();
        for(int i=0;i
            if(nums[i]>0)break;
            if(i>0&&nums[i]==nums[i-1])continue;
            int j=i+1;
            int k=nums.length-1;
            while(j
                int sum=nums[i]+nums[j]+nums[k];
                if(sum<0){
                    while(j0){
                    while(j
                    res.add(new ArrayList(Arrays.asList(nums[i], nums[j], nums[k])));
                    while(j 
2. 17.电话号码的字母组合 
1.题目描述 

2. 题目解析

首先看到所有组合,就可以想到回溯。

回溯模板:

  • 全局变量: 保存结果;
  • 参数设计: 状态变量和条件变量。一个是最后结果要保存的值,一个是决定搜索是否完毕或者合法的值;
  • 完成条件: 完成条件是决定 状态变量和条件变量 在取什么值时可以判定整个搜索流程结束。搜索流程结束有两种含义: 搜索成功并保存结果 和 搜索失败并返回上一次状态。
  • 递归过程: 传递当前状态给下一次递归进行搜索。
result = []//全局变量,存储结果
void backtrack(全局变量result,条件变量,状态变量):
    if (满足结束条件){
        result.add(状态变量);
        return;
    }
    else  if(不合法){
    	剪枝
    	return;
    } 
    # 主要递归过程,一般是带有 循环体 或者 条件体
    for(满足执行条件){
        做选择;
        backtrack(全局变量result,条件变量,状态变量);
        撤销选择;
    }
class Solution {
    public List letterCombinations(String digits) {
        if(digits.length()==0){
            return new ArrayList();
        }
        Listres=new ArrayList<>();
        Map phone=new HashMap<>();
        phone.put('2',"abc");
        phone.put('3',"def");
        phone.put('4',"ghi");
        phone.put('5',"jkl");
        phone.put('6',"mno");
        phone.put('7',"pqrs");
        phone.put('8',"tuv");
        phone.put('9',"wxyz");
        dfs(res,phone,digits,0,new StringBuffer());
        return res;
    }
    public void dfs(List res, Map phoneMap, String digits, int index, StringBuffer tmp){
        if(index==digits.length()){
            res.add(tmp.toString());
            return;
        }
        char digit = digits.charAt(index);
        String letters = phoneMap.get(digit);
        int lettersCount = letters.length();
        for (int i = 0; i < lettersCount; i++) {
            tmp.append(letters.charAt(i));
            dfs(res, phoneMap, digits, index + 1, tmp);
            tmp.deleteCharAt(index);
        }
    }
}

注意:string==""与string.length()==0与string==null 的区别。

3. 19.删除链表的倒数第 N 个结点 1.题目描述

2. 题目解析

在对链表进行操作时,一种常用的技巧是添加一个哑节点(dummy node),它的 next 指针指向链表的头节点。这样一来,我们就不需要对头节点进行特殊的判断了。

1. 方法一:获取长度再找到要删除的结点

删去倒数第n个结点,首先需要获取到链表结点个数L,然后再获取到第L-n即可,它的下一个即L-n+1个即为要删除的结点。

问题在于如果删除后,还要将头结点输出?

上边提到,增加一个结点可以将头结点问题统一;
所以首先增加一个哑结点,然后将一个指针指向它,再进行遍历,找到第L-n+1个结点,去除第L-n+1的下一个结点,输出哑结点的下一个即可。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode h=new ListNode(0,head);
        int l=getLength(head);
        ListNode cur=h;
        for(int i=1;i
            cur=cur.next;
        }
        cur.next=cur.next.next;
        return h.next;
    }

    public int getLength(ListNode head) {
        int res=0;
        ListNode tmp=head;
        while(tmp!=null){
            res++;
            tmp=tmp.next;
        }
        return res;
    }
}

2. 方法二:栈

删除倒数第n个,将链表倒过来删除第n个结点即可。

首先将所有结点压入栈,然后抛出前n个结点,则栈顶结点就是要删除结点的前一个,所以只要将该结点的下一个指向下一个的下一个即可删除。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        Stack stack = new Stack();
        ListNode cur = dummy;
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        for (int i = 0; i < n; ++i) {
            stack.pop();
        }
        ListNode prev = stack.peek();
        prev.next = prev.next.next;
        ListNode ans = dummy.next;
        return ans;
    }
}

栈在Java中使用Stack和Deque(双端队列)都可以。

3. 方法三:快慢指针

即使不知道链表的长度,也可以获取倒数第n个结点,只需要快慢指针即可:一个指针first超前另一个指针second n-1个结点,则当first指针走到最后时,second指针所在的即为倒数第n个。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode h = new ListNode(0, head);
        ListNode first = h;
        ListNode second = h;
        for (int i = 0; i <= n; ++i) {
            first = first.next;
        }
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        second.next = second.next.next;
        return h.next;
    }
}
4. 20.有效的括号 1.题目描述

2. 题目解析

括号是否匹配主要有两个条件:1.左右括号同类型匹配,2.匹配顺序正确。对于条件1,我们只需做一个判断即可;对于条件2,正确顺序就是先出现左括号,就要先匹配对应的右括号,所以就是后来的先匹配走,对应栈,先进后出。

所以首先遍历字符串,左括号进栈,对于右括号,只需要判断栈顶元素是否是匹配的,如果不匹配直接返回false,匹配则直接推出栈顶元素。遍历完毕后如果栈为空,则完成匹配,否则返回false。

class Solution {
    public boolean isValid(String s) {
        Stackstack=new Stack<>();
        for(int i=0;i
            if(s.charAt(i)=='('||s.charAt(i)=='['||s.charAt(i)=='{'){
                stack.push(s.charAt(i));
            }
            else if(s.charAt(i)==')'&&!stack.empty()&&stack.peek()=='('){
                stack.pop();
            }
            else if(s.charAt(i)==']'&&!stack.empty()&&stack.peek()=='['){
                stack.pop();
            }
            else if(s.charAt(i)=='}'&&!stack.empty()&&stack.peek()=='{'){
                stack.pop();
            }
            else{
                return false;
            }
        }
        if(stack.empty()){
            return true;
        }
        return false;
    }
}
5. 21.合并两个有序链表 1. 题目描述

2. 题目解析

合并两个升序链表,首先新建一个哑结点,然后用一个指针cur指向结点,用两个指针分别指向两个链表的头部,比较两个结点的大小,取值小的结点为cur的下一个结点,然后将指向该结点的指针后移,直至一条链表遍历完毕,然后将cur指向不为空的链表即可。

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode n1=list1;
        ListNode n2=list2;
        ListNode head=new ListNode(0);
        ListNode cur=head;
        while(n1!=null&&n2!=null){
            if(n1.val<=n2.val){
                cur.next=n1;
                n1=n1.next;
            }else{
                cur.next=n2;
                n2=n2.next;
            }
            cur=cur.next;
        }
        if(n1==null){
            cur.next=n2;
        }
        else{
            cur.next=n1;
        }
        return head.next;
    }
}

递归:
题解中有递归实现,同理。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/934886.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号