宝,我今天刷题了(leetcode刷题笔记 15、19)

496 阅读1分钟

这是我参与更文挑战的第7天,活动详情查看: 更文挑战

题目地址:leetcode-cn.com/problems/3s…

15题

题目描述:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

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

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

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

提示:

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

暴力求解

step1:如何去除重复的?要使取出的三个数不重复,我们可以以依次取出三个有序的数a<=b<=c 这样因为a+b+c = 0。取数的思路是:

先取a,如果a与上一次a相同则跳过取下一个;

再取b, b在当前a之后的 如果b与上次的b相同则跳过取下一个

同理取c c如果与上一次的c相同则跳过。

step2:判断当前取出的三个数之和是否为0

因为当最小的数大于0时三数之和不可能为0,直接退出循环

参考代码:

/**
     * 暴力求解
     */
    List<List<Integer>> solution1(int[] nums) {
        Arrays.sort(nums);
        int length = nums.length;
        int lastI = Integer.MAX_VALUE, lastJ, lastK;
        List<List<Integer>> arrayList = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            if (lastI == nums[i]) {
                continue;
            }
            if(lastI > 0){
                break;
            }
            //进入下一轮循环的时候
            lastJ = Integer.MAX_VALUE;
            lastI = nums[i];
            for (int j = i + 1; j < length; j++) {
                if (lastJ == nums[j]) {
                    continue;
                }
                lastJ = nums[j];
                lastK = Integer.MAX_VALUE;
                for (int k = j + 1; k < length; k++) {
                    if (lastK == nums[k]) {
                        continue;
                    }
                    lastK = nums[k];
                    if (lastI + lastJ + lastK == 0) {
                        ArrayList<Integer> integerArrayList = new ArrayList<>();
                        integerArrayList.add(lastI);
                        integerArrayList.add(lastJ);
                        integerArrayList.add(lastK);
                        arrayList.add(integerArrayList);
                    }
                }
            }
        }
        System.out.println("solution1  size " + arrayList.size());
        return arrayList;
    }

双指针

优先取出最小数,当三数之和小于0是增加中间那个数,当三数之和大于0时减小最大数 双指针.png

参考代码:

List<List<Integer>> solution2(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> arrayList = new ArrayList<>();
        int lastI = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] == lastI){
                continue;
            }
            lastI = nums[i];
            int start=i+1, end = nums.length - 1;
            int lastStart = Integer.MAX_VALUE;
            int lastEnd = Integer.MAX_VALUE;
            boolean changeStart = true;
            while (start<end){
                if(lastStart == nums[start] && changeStart){
                    start++;
                    continue;
                }
                if(lastEnd == nums[end] && !changeStart){
                    end--;
                    continue;
                }
                lastStart = nums[start];
                lastEnd = nums[end];
                int result = nums[i]+nums[start]+nums[end];
                if(result > 0){
                    changeStart = false;
                    end--;
                }else if(result < 0){
                    changeStart = true;
                    start++;
                }else {
                    ArrayList<Integer> integerArrayList = new ArrayList<>();
                    integerArrayList.add(nums[i]);
                    integerArrayList.add(nums[start]);
                    integerArrayList.add(nums[end]);
                    arrayList.add(integerArrayList);
                    start++;
                    changeStart = true;
                }
            }
        }
        return arrayList;
    }

19题

题目地址:leetcode-cn.com/problems/re…

题目描述:

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

题解:

因为题目要求使用一趟扫描,我们很容易想到使用双指针来进行解题。

双指针删除.png

假设我们要求倒数第2个,为了不保存过多的数据,当后面的指针到空的时候,前一个指针正好落在3的位置,此时它的下一个元素就是我们眼删除的。即:13,24,35 我们用count记录前一个指针走的步数。当count大于n时前指针开始移动。

特殊情况 :

n 大于链表的长度,此时不需要删除元素

n等于链表长度,此时需要删除的是头结点

参考代码:

 public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head == null){
            return null;
        }
        ListNode h = head;
        ListNode pre = head;
        int count = 0;
        while (pre!=null){
            if(count>n){
                h = h.next;
            }
            pre = pre.next;
            count++;
        }
        if(count>n){//已经走动需要删除
            ListNode temp = h.next;
            h.next = temp.next;
        }else if(count == n){//要删除的是头指针
            head = h.next;
        }
        return head;
    }