LeetCode138. 复制带随机指针的链表/1893. 检查是否区域内所有整数都被覆盖/370. 区间加法(差分数组+前缀和)

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode138. 复制带随机指针的链表/1893. 检查是否区域内所有整数都被覆盖/370. 区间加法(差分数组+前缀和)相关的知识,希望对你有一定的参考价值。

138. 复制带随机指针的链表

2021.7.22 每日一题

题目描述

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:

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

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:

输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

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

思路

剑指offer的原题
这里的关键点是处理随机指针,我想到的思路是,将原节点和新节点对应,放在一个哈希表中,然后就能在一次遍历中快速的查到指向的节点。
在写的过程中,发现index指针是移动的,那么直接存index可以吗,有这个疑问。后面也想明白了,index就是一个原链表的节点,所以map存储的也是这个节点,而不是一个移动的指针,所以是可以的

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {
    public Node copyRandomList(Node head) {
        //主要是随机指针怎么复制
        //这边用一个map,存储原节点对应的新节点
        Node dummy = new Node(-1);
        Node index = head;
        Node newid = dummy;
        Map<Node, Node> map = new HashMap<>();
        while(index != null){
            Node node = new Node(index.val);
            newid.next = node;
            newid = newid.next;
            //这样存行吗??????
            map.put(index, node);
            index = index.next;
        }

        index = head;
        newid = dummy.next;
        while(index != null){
            Node ran = index.random;
            Node newran = map.get(ran);
            newid.random = newran;
            newid = newid.next;
            index = index.next;
        }
        return dummy.next;

    }
}

另一个思路,将新建的节点放在原节点后面,这样做的好处是,可以很快找到对应的随机节点,也不用map的空间

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {
    public Node copyRandomList(Node head) {
        //主要是随机指针怎么复制
        //这边用一个map,存储原节点对应的新节点
        if(head == null)
            return null;
        Node dummy = new Node(-1);
        Node index = head;

        
        //新节点接在原节点后面
        while(index != null){
            Node node = new Node(index.val);
            node.next = index.next;
            index.next = node;
            index = node.next;
        }

        //处理随机指针
        index = head;
        while(index != null){
            Node ran = index.random;
            if(ran != null)
                index.next.random = ran.next;
            index = index.next.next;
        }
        //分割两个链表
        index = head;
        dummy.next = head.next;
        Node id = dummy;
        while(index != null){
            id.next = index.next;
            id = id.next;
            index.next = id.next;
            index = index.next;
        }
        return dummy.next;

    }
}

1893. 检查是否区域内所有整数都被覆盖

题目描述

给你一个二维整数数组 ranges 和两个整数 left 和 right 。每个 ranges[i] = [starti, endi] 表示一个从 starti 到 endi 的 闭区间 。

如果闭区间 [left, right] 内每个整数都被 ranges 中 至少一个 区间覆盖,那么请你返回 true ,否则返回 false 。

已知区间 ranges[i] = [starti, endi] ,如果整数 x 满足 starti <= x <= endi ,那么我们称整数x 被覆盖了。

示例 1:

输入:ranges = [[1,2],[3,4],[5,6]], left = 2, right = 5
输出:true
解释:2 到 5 的每个整数都被覆盖了:

  • 2 被第一个区间覆盖。
  • 3 和 4 被第二个区间覆盖。
  • 5 被第三个区间覆盖。
    示例 2:

输入:ranges = [[1,10],[10,20]], left = 21, right = 21
输出:false
解释:21 没有被任何一个区间覆盖。

提示:

1 <= ranges.length <= 50
1 <= starti <= endi <= 50
1 <= left <= right <= 50

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/check-if-all-the-integers-in-a-range-are-covered
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

周赛做过的题,怎么最近老出周赛的题…
排序,遍历就行了

class Solution {
    public boolean isCovered(int[][] ranges, int left, int right) {
        Arrays.sort(ranges, (a, b) -> ((a[0] == b[0]) ? a[1] - b[1] : a[0] - b[0]));
        int index = left;
        int l = ranges.length;
        for(int[] range : ranges){
            int ll = range[0];
            int rr = range[1];
            if(index >= range[0] && index <= range[1]){
                index = range[1] + 1;    
                if(index > right){
                   return true;
                }
            }
        }
        return false;

    }
}

学一下差分数组,没看懂官解是在说什么
差分数组,首先明确定义:差分数组 diff 维护相邻两个整数的被覆盖区间数量变化量
其中 diff[i] 对应覆盖整数 i 的区间数量相对于覆盖 i − 1 的区间数量变化量
啥意思呢,如果在区间开始位置 i ,那么diff[i]就加1,意思是就是说在这个位置相比于前面的位置,多了一个区间覆盖
如果在区间结束位置i,diff[i + 1]就减1,意思就是说i+1这个位置比i位置少一个区间覆盖

这样,对差分数组求前缀和,就可以得到每个位置被覆盖的次数

class Solution {
    public boolean isCovered(int[][] ranges, int left, int right) {
        //差分数组学习一下
        //首先明确定义:差分数组 diff 维护相邻两个整数的被覆盖区间数量变化量
        //其中 diff[i] 对应覆盖整数 i 的区间数量相对于覆盖 i − 1 的区间数量变化量
        //啥意思呢,如果在区间开始位置 i ,那么diff[i]就加1,意思是就是说在这个位置相比于前面的位置,多了一个区间覆盖
        //如果在区间结束位置i,diff[i + 1]就减1,意思就是说i+1这个位置比i位置少一个区间覆盖

        //这样,对差分数组求前缀和,就可以得到每个位置被覆盖的次数
        
        //总共0到50共51个数,因为可能i+1多出一个数,所以定义长度为52
        int[] diff = new int[52];
        for(int[] range : ranges){
            diff[range[0]]++;
            diff[range[1] + 1]--;
        }

        //计算前缀和
        int[] pre = new int[51];
        pre[0] = diff[0];
        for(int i = 1; i <= 50; i++){
            pre[i] = pre[i - 1] + diff[i];
        }

        for(int i = left; i <= right; i++){
            if(pre[i] == 0)
                return false;
        }
        return true;
    }
}

370. 区间加法

题目描述

假设你有一个长度为 n 的数组,初始情况下所有的数字均为 0,你将会被给出 k​​​​​​​ 个更新的操作。

其中,每个操作会被表示为一个三元组:[startIndex, endIndex, inc],你需要将子数组 A[startIndex … endIndex](包括 startIndex 和 endIndex)增加 inc。

请你返回 k 次操作后的数组。

示例:

输入: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
输出: [-2,0,3,5,3]
解释:

初始状态:
[0,0,0,0,0]

进行了操作 [1,3,2] 后的状态:
[0,2,2,2,0]

进行了操作 [2,4,3] 后的状态:
[0,2,5,5,3]

进行了操作 [0,2,-2] 后的状态:
[-2,0,3,5,3]

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

思路

差分数组练习

class Solution {
    public int[] getModifiedArray(int length, int[][] updates) {
        //差分数组做一下
        //即对每个区间加上对应的inc
        int l = updates.length;
        int[] diff = new int[length + 1];
        for(int i = 0; i < l; i++){
            int left = updates[i][0];
            int right = updates[i][1];
            int inc = updates[i][2];
            diff[left] += inc;
            diff[right + 1] -= inc;
        }

        int[] res = new int[length];
        res[0] = diff[0];
        for(int i = 1; i < length; i++){
            res[i] = res[i - 1] + diff[i];
        }
        return res;
    }   
}

以上是关于LeetCode138. 复制带随机指针的链表/1893. 检查是否区域内所有整数都被覆盖/370. 区间加法(差分数组+前缀和)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 138 复制带随机指针的链表

LeetCode Algorithm 138. 复制带随机指针的链表

LeetCode Algorithm 138. 复制带随机指针的链表

Leetcode刷题Python138. 复制带随机指针的链表

[LeetCode]138复制带随机指针的链表

LeetCode Java刷题笔记—138. 复制带随机指针的链表