力扣大厂热门面试算法题 18-20

58 篇文章 1 订阅
55 篇文章 0 订阅
本文详细解析了LeetCode中的三道题目:四数之和的双指针解决方案、删除链表倒数第N个结点的迭代方法,以及有效括号的栈操作技巧,提供了Python和Java的实现代码。
摘要由CSDN通过智能技术生成

       18. 四数之和,19. 删除链表的倒数第 N 个结点,20. 有效的括号 ,每题做详细思路梳理,配套Python&Java双语代码, 2024.03.12 可通过leetcode所有测试用例

目录

18. 四数之和

 解题思路

完整代码

Python

Java

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

 解题思路

完整代码

Python

Java

20. 有效的括号

 解题思路

完整代码

Python

Java


18. 四数之和

        给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

示例 1:

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

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
 

 解题思路

可以通过使用双指针法加上两层循环的方式来解决,主要步骤如下:

  1. 排序:首先对数组进行排序,这样可以方便后续去重以及使用双指针法。

  2. 遍历:使用两层循环遍历数组,第一层循环枚举第一个数,第二层循环枚举第二个数。

  3. 双指针:在每一对固定的第一和第二个数后,使用两个指针分别指向剩余部分的开始和结束位置,移动指针寻找满足条件的四元组。

  4. 去重:在遍历和双指针移动的过程中,需要注意去重。

完整代码

Python
class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        res = []

        for i in range(n):
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            for j in range(i + 1, n):
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue

                left, right = j + 1, n - 1
                while left < right:
                    total = nums[i] + nums[j] + nums[left] + nums[right]
                    if total < target:
                        left += 1
                    elif total > target:
                        right -= 1
                    else:
                        res.append([nums[i], nums[j], nums[left], nums[right]])
                        while left < right and nums[left] == nums[left + 1]:
                            left += 1
                        while left < right and nums[right] == nums[right - 1]:
                            right -= 1
                        left += 1
                        right -= 1

        return res
Java
public class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        int n = nums.length;

        for (int i = 0; i < n; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < n; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) continue;

                int left = j + 1, right = n - 1;
                while (left < right) {
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum < target) {
                        left++;
                    } else if (sum > target) {
                        right--;
                    } else {
                        res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while (left < right && nums[left] == nums[left + 1]) left++;
                        while (left < right && nums[right] == nums[right - 1]) right--;
                        left++;
                        right--;
                    }
                }
            }
        }
        return res;
    }
}

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

给你一个链表,删除链表的倒数第 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]
 

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
 

 解题思路

        删除链表的倒数第n个节点可以通过一次遍历完成,主要思路是使用两个指针:快指针和慢指针。首先让快指针向前移动n步,然后快慢指针同时移动,直到快指针指向链表末尾。此时,慢指针的下一个节点就是需要删除的节点。具体步骤如下:

  1. 创建一个哑结点:哑结点指向链表的头部,这样做的好处是可以简化对头结点进行操作的复杂度,尤其是当头结点需要被删除时。

  2. 初始化快慢指针:快慢指针都指向哑结点。

  3. 移动快指针:快指针向前移动n+1步,这样快慢指针之间就保持了n个节点的距离。

  4. 同时移动快慢指针:快慢指针同时向前移动,直到快指针指向链表末尾的null。

  5. 删除节点:此时慢指针的下一个节点就是需要删除的节点,通过修改慢指针的next指针来跳过这个节点。

完整代码

Python
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(0, head)
        fast = slow = dummy

        # 快指针先前移n+1步
        for _ in range(n + 1):
            fast = fast.next

        # 快慢指针同时移动直到快指针到达末尾
        while fast:
            fast = fast.next
            slow = slow.next

        # 删除倒数第n个节点
        slow.next = slow.next.next
        return dummy.next
Java
public class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode fast = dummy, slow = dummy;

        // 快指针先前移n+1步
        for (int i = 1; i <= n + 1; i++) {
            fast = fast.next;
        }

        // 快慢指针同时移动直到快指针到达末尾
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }

        // 删除倒数第n个节点
        slow.next = slow.next.next;
        return dummy.next;
    }
}

20. 有效的括号

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

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
 

示例 1:

输入:s = "()"
输出:true
示例 2:

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

输入:s = "(]"
输出:false
 

提示:

1 <= s.length <= 104
s 仅由括号 '()[]{}' 组成

 解题思路

        判断括号字符串是否有效的一个常用方法是使用栈。基本思想是遍历字符串,每次遇到一个左括号就将其推入栈中,每次遇到一个右括号就检查栈顶元素是否为对应的左括号,如果是,则将栈顶元素弹出;如果不是或栈为空,则说明字符串无效。遍历结束后,如果栈为空,则说明所有括号都正确匹配,字符串有效;如果栈不为空,则说明有未匹配的左括号,字符串无效。

完整代码

Python
class Solution:
    def isValid(self, s: str) -> bool:
        stack = []
        mapping = {")": "(", "}": "{", "]": "["}

        for char in s:
            if char in mapping:
                top_element = stack.pop() if stack else '#'
                if mapping[char] != top_element:
                    return False
            else:
                stack.append(char)

        return not stack
Java
class Solution {
    public boolean isValid(String s) {
        Deque<Character> stack = new ArrayDeque<>();
        Map<Character, Character> mapping = new HashMap<>();
        mapping.put(')', '(');
        mapping.put('}', '{');
        mapping.put(']', '[');

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (mapping.containsKey(c)) {
                char topElement = stack.isEmpty() ? '#' : stack.pop();
                if (mapping.get(c) != topElement) {
                    return false;
                }
            } else {
                stack.push(c);
            }
        }

        return stack.isEmpty();
    }
}
  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昊昊该干饭了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值