Leetcode记录库数据结构篇之一:链表

【LeetCode刷题——数据结构篇】 2022寒假LeetCode刷题——Task01:链表 简介:本人大一学过C++,此后几年间几乎没有使用过,可以称得上是小白了。所以此次刷题会是比较困难的过程,同时也是通过这次的组队学习捡拾起以前的知识,更重要是扩充和巩固。所以这篇blog篇幅可能较长且也有基础型知识的回顾,也是我在做题过程中一步步完成的记录。 一、数组基础题目 (题号:0189)旋转数组 题目:给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 首先要弄清楚的点: vector和array的区别 双指针法 ... 阅读详情

结论

记录一些很主观的东西,有些想法归根结底可能还是自己的实力不够。
与链表有关的算法题,一般需要进行以下考虑:

1.区分所操作节点的类型:首结点、中间节点、尾节点。
2.如果需要对头结点进行相关操作,那么考虑是否要添加虚拟头结点。
3.如果一个问题涉及到数据的顺序和要进行的操作相逆的话,考虑使用栈结构转存。而且使用数组栈效率高一点。

1 160.相交链表

https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

思路描述

  • 如果两个链表相交的话,那么他们必有交叉的地方,如图:
    在这里插入图片描述
    而且不会是这样的交叉:
    在这里插入图片描述
    因为链表中的节点只会有一个后继节点。 所以有a+c+b = b+c+a,顺序遍历两个链表,当某个链表结束时,开始遍历另一个链表,直到节点相等。

代码实现

  • java代码:
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode a = headA;
        ListNode b = headB;
        while (a != b) {
            a = a != null ? a.next : headB;
            b = b != null ? b.next : headA;
        }

        return a;
    }
}

注意事项

  • 无

拓展延伸

  • 如果只是判断是否存在交点,那么就是另一个问题,即 编程之美 3.6 的问题。
    有两种解法:把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;或者直接比较两个链表的最后一个节点是否相同。

2 206.反转链表

https://leetcode-cn.com/problems/reverse-linked-list/

思路描述

  • 2019年考研408试卷原题,如果我那年复习的时候不那么投机取巧,这道题就能做上了,明明这么简单。55555……
    头插法原地逆置链表,时间复杂度O(n),空间复杂度O(1)。

代码实现

  • java代码:
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null) return head;

        ListNode newhead, temp, node;
        //取下需要逆转的链表的第一个,作为新链表的结尾
        newhead = head;
        head = head.next;
        //结尾置空
        newhead.next = null;

        while(head != null){
            node = head;//先记录下当前需要操作的节点
            temp = head.next;//记录下下一个要操作的节点
            node.next = newhead;//当前操作节点接到逆转后的链表的头部
            newhead = node;//当前操作节点成为逆转后链表的新头
            head = temp;//未逆转链表的新头
        }
        return newhead;
    }
}

注意事项

  • 1.java中对于链表节点“=”等号赋值好像是两个变量公用一个内存单元,所以说修改一个变量的next,另一个变量的next也已经变了。

拓展延伸
递归的解法:

public ListNode reverseList(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    ListNode next = head.next;
    ListNode newHead = reverseList(next);
    next.next = head;
    head.next = null;
    return newHead;
}

3 21.归并有序链表

https://leetcode-cn.com/problems/merge-two-sorted-lists/

思路描述
woshishabi.

代码实现

  • java代码:
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;

        ListNode tempNode, newhead, newtail;
        if(l1.val <= l2.val){
            newhead = l1;
            newtail = l1;
            l1 = l1.next;
        }else{
            newhead = l2;
            newtail = l2;
            l2 = l2.next;
        }

        while(l1 != null && l2 != null){
            while((l1 != null && l2 != null) && l1.val <= l2.val){
                newtail.next = l1;
                newtail = l1;
                l1 = l1.next;
            }

            while((l1 != null && l2 != null) && l2.val <= l1.val){
                newtail.next = l2;
                newtail = l2;
                l2 = l2.next;
            }
        }
        newtail.next = (l2 == null)? l1 : l2;

        return newhead;
    }
}

注意事项

  • 1.脑袋不清楚的时候别写代码!!!
  • 2.脑袋不清楚的时候别写代码!!!
  • 3.脑袋不清楚的时候别写代码!!!

拓展延伸
递归的解法:

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    if (l1 == null) return l2;
    if (l2 == null) return l1;
    if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}

4 83. 删除排序链表中的重复元素

https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/

思路描述
这也算是双指针吧,一快一慢,如果快指针的val和慢指针的val相同,快指针就向后移。直到链表结束。

代码实现
java代码:

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null) return head;
        ListNode l1 = head, l2 = head;
        while(l2 != null){
            while(l2 != null && l1.val == l2.val){
                l2 = l2.next;
            }
            l1.next = l2;
            l1 = l2;
        }
        return head;
    }
}

注意事项

  • 1.在取指针的值之前,需要注意先确定指针是否为空。

拓展延伸
递归的解法:

public ListNode deleteDuplicates(ListNode head) {
    if (head == null || head.next == null) return head;
    head.next = deleteDuplicates(head.next);
    return head.val == head.next.val ? head.next : head;
}

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

https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/

思路描述

  • 1.删除一个链表的头,我们需要将链表的头改变。
    2.删除一个链表中间的一个节点,我们需要知道这个节点的前一个节点和后一个节点,然后将两者相连。
    3.需要删除的是尾节点,和2一样。 基本原理:双指针,一快一慢,中间相差k步。一个指需被删节点前,一个指链表尾。

代码实现
java代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // 前置处理
        if(head == null || n == 0) return head;
        else if(head.next == null){
            head = null;
            return head;
        }

        // 确定prior和tail之间的距离
        ListNode prior = head, tail = head;
        do{
            tail = tail.next;
            n--;
        }while(n != 0);

        // 需要删除的是头结点
        if(tail == null){
            return head.next;
        }

        // 否则,双指针同步后移,遍历列表
        while(tail.next != null){
            prior = prior.next;
            tail = tail.next;
        }

        // 删除节点
        prior.next = prior.next.next;

        return head;
    }
}

注意事项

  • 1.在对指针进行操作时,一定要注意区分,节点的类型,链表中的节点分为三种:头结点、中间节点、尾节点,在对他们操作时需要注意。

拓展延伸

  • 无

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

https://leetcode-cn.com/problems/swap-nodes-in-pairs/

思路描述

  • 1.先试试递归:如下。但是这样每一层都会定义两个变量,空间复杂度是O(n)了。

代码实现
java代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null) return head;

        ListNode swap = head, temp = head.next.next;
        head = head.next;
        head.next = swap;
        swap.next = swapPairs(temp);

        return head;
    }
}

思路描述

  • 2.再试试常规解法:
    交换前后两个节点,我们需要知道: (从这里开始走偏了)一个窗口大小为4的链表段的节点指针。(最后还是变递归了,而且还很繁琐)
  • 其实我们需要知道的是,这两个节点的前置节点就好了。交换3号和4节点,我们只需要知道2号节点既可以了。但是,交换1号和2号,我们需要表头节点,没有的话虚拟出一个来。这就有了拓展延伸的方法。

代码实现
java代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        // 
        if(head == null || head.next == null){
            return head;
        } 
        if(head.next.next == null){
            ListNode swap = head.next;
            swap.next = head;
            head.next = null;
            return swap;
        } 

        if(head.next.next.next == null){
            ListNode swap = head.next, tail = head.next.next;
            swap.next = head;
            head.next = tail;
            return swap;
        } 

        ListNode p1, p2, p4, newhead = head.next, swap;
        while(head.next.next.next != null){
            p1 = head;
            p2 = head.next;
            p4 = head.next.next.next;
            head = head.next.next;

            swap = p2;
            swap.next = p1;
            p1.next = p4;

            if(head == null || head.next == null){
                return newhead;
            } 

            if(head.next.next == null){
                swap = head.next;
                swap.next = head;
                head.next = null;

                return newhead;
            } 

            if(head.next.next.next == null){
                swap = head.next;
                ListNode tail = head.next.next;
                swap.next = head;
                head.next = tail;

                return newhead;
            } 
        } 
        return newhead;
    }
}

注意事项

  • 1.在对指针进行操作时,一定要注意区分,节点的类型,链表中的节点分为三种:头结点、中间节点、尾节点,在对他们操作时需要注意。

拓展延伸

  • 1.在链表头之前加一个虚拟节点,便可迎刃而解。时间复杂度O(n),空间O(1)
class Solution {
    public ListNode swapPairs(ListNode head) {
        // 设置一个链表头结点的前置节点
        ListNode node = new ListNode(-1);
        node.next = head;
        
        ListNode pre = node;
        while (pre.next != null && pre.next.next != null) {
            ListNode l1 = pre.next, l2 = pre.next.next;
            ListNode next = l2.next;
            l1.next = next;
            l2.next = l1;
            pre.next = l2;

            pre = l1;
        }
        return node.next;   
    }
}

7 445. 两数相加 II

题目

思路描述

  • 1.应该是要用递归,倒着从最后一位加过来,因为会涉及到链表头,所以需要新建一个头结点。
  • 不行,递归做不出来
  • 因为本题是需要对 两个链表 同时处理。
  • 也就是说对 两个链表是并行处理的关系。而递归一般只能对一个 变量做递归处理;那么处理2个链表就成了串行处理,无法做累加。也不是不能用递归对两个链表处理,但是里面还涉及到对齐的问题;特别是因为节点数不一样,一个到链表尾,另一个没到,还是需要递归。
  • 也就是说,如果两个链表的节点个数是 一样 ,那就可以把两个链表,抽象成一个来处理。

代码实现
java代码:

思路描述

  • 1.使用栈结构保存链表内容,然后一一相加,使用头插法建立链表进行存储。

代码实现
java代码:

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 引入栈结构
        Stack<Integer> stack1 = listToStack(l1);
        Stack<Integer> stack2 = listToStack(l2);

        // 初始化进位
        int carry = 0, a = 0, b = 0, result;

        // 初始化返回的链表头结点
        ListNode newhead = new ListNode(-1, null);
        while(!stack1.isEmpty() || !stack2.isEmpty() || carry != 0){
            a = stack1.isEmpty() ? 0 : stack1.pop();
            b = stack2.isEmpty() ? 0 : stack2.pop();
            result = a + b + carry;
            carry = result / 10;
            result = result % 10;

            // 头插法建立链表,保证顺序
            ListNode node = new ListNode(result);
            node.next = newhead.next;
            newhead.next = node;
        }

        return newhead.next;
    }

    // 私有方法将链表中的val存放到栈中
    private Stack<Integer> listToStack(ListNode l){
        Stack<Integer> stack = new Stack<>();
        while(l != null){
            stack.push(l.val);
            l = l.next;
        }

        return stack;
    }
}

注意事项

  • 注意事项

拓展延伸

  • 如果一个问题涉及到数据的顺序和要进行的操作相逆的话,考虑使用栈结构转存。而且使用数组栈效率高一点。
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 引入数组栈结构
        int stack1[] =new int[100], top1 = -1;
        while(l1 != null){
            stack1[++top1] = l1.val;
            l1 = l1.next;
        }

        int stack2[] = new int[100], top2 = -1;
        while(l2 != null){
            stack2[++top2] = l2.val;
            l2 = l2.next;
        }

        // 初始化进位
        int carry = 0, a = 0, b = 0, result;

        // 初始化返回的链表头结点
        ListNode newhead = new ListNode(-1, null);
        while(top1 != -1 || top2 != -1 || carry != 0){
            a = (top1 == -1) ? 0 : stack1[top1--];
            b = (top2 == -1) ? 0 : stack2[top2--];
            result = a + b + carry;
            carry = result / 10;
            result = result % 10;

            //System.out.println(top1);

            // 头插法建立链表,保证顺序
            ListNode node = new ListNode(result);
            node.next = newhead.next;
            newhead.next = node;
        }

        return newhead.next;
    }
}

8 234. 回文链表

题目

思路描述

  • 回文链表,从中间分开两边是对称的。这需要对链表的长度进行区分是偶数还是奇数。
  • 1.偶数:使用双指针,快指针一次移动两个位置,慢指针一次一个,同时使用栈结构将内容存下来,然后从慢指针这里继续往后遍历,同时出栈判断元素是否相同。
  • 2.奇数:原理相同,不过在判断元素是否相同时,栈结构要先出栈一个。
  • 时空间复杂度为O(n)和O(n);

代码实现
java代码:

class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head.next == null) return true;

        // 
        ListNode fast = head, slow = head;
        int i = 0;
        Stack<Integer> stack = new Stack<>();
        while(fast != null){
            i++;
            stack.push(slow.val);
            // fast后移两个并进行判断链表是否结束
            fast = fast.next;
            if(fast == null) break;
            else {
                i++;
                fast = fast.next;
            }
            if(fast == null) break;

            // slow后移一个
            slow = slow.next;
        }

        // 区分链表的长度
        if(i % 2 == 0){// 偶数
            slow = slow.next;
            while(slow != null){
                if(slow.val != stack.pop()){
                    return false;
                }
                slow = slow.next;
            }
        }else{// 奇数
            i = stack.pop();
            slow = slow.next;
            while(slow != null){
                if(slow.val != stack.pop()){
                    return false;
                }
                slow = slow.next;
            }
        }
        return true;
    }
}

思路描述

  • 没说不能破坏原有链表,那么还是快慢指针,等到快指针移动到最后时,区分链表长度的是技术还是偶数,将后半部分逆置。
  • 然后遍历前半部分和被逆置的后半部分链表,查看是否相同。
  • 时空间复杂度O(n)和O(1)

代码实现
java代码:

class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null) return true;

        // 
        ListNode fast = head.next, slow = head, temp;
        ListNode newhead = new ListNode(-1, null);
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }

        //开始逆置后续链表
        if(fast == null){// 链表长度为奇数
            while(slow != null){
                temp = slow.next;
                slow.next = newhead.next;
                newhead.next = slow;
                slow = temp;
            }
        }else{// 链表长度为偶数
            slow = slow.next;
            while(slow != null){
                temp = slow.next;
                slow.next = newhead.next;
                newhead.next = slow;
                slow = temp;
            }
        }

        // 判断元素是否相同
        while(newhead.next != null){
            if(head.val == newhead.next.val){
                
            }else{
                return false;
            }

            head = head.next;
            newhead = newhead.next;
        }

        return true;
    }
}

注意事项

  • 1.快指针和慢指针的位置关系。

拓展延伸

  • 快慢指针之间的距离关系,标准写法。
  • 比如说想要快慢指针位置关系为1:2
        ListNode fast = head.next, slow = head;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
  • 1:3
        ListNode fast = head.next.next, slow = head;
        while(fast != null && fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next.next;
        }

9 725. 分隔链表

题目

思路描述

  • 1.首先获取链表的长度,然后判断链表够不够长。也就是说len是否大于k,如果不大于则不够长,结果中肯定有空链表。而且各个非空链表肯定长度为1。
  • 2.如果够长则需要考虑怎么将链表进行划分,才能满足题目要求。靠前的链表长而且只会比后面的列表长1个单位。所以首先将链表均分,然后剩下的长度,从头依次向后添加给每个需要划分的小链链表,直到用光。

代码实现
java代码:

class Solution {
    public ListNode[] splitListToParts(ListNode head, int k) {
        // 预处理
        if(k == 1) {
            ListNode[] array = new ListNode[k];
            array[0] = head;
            return array;
        }

        // 获取链表的长度
        ListNode h = head;
        int len = 0;
        while(h != null){
            len++;
            h = h.next;
        }

        // 分割后链表最佳长度
        int lenSplited = len / k;
        // 链表平分后剩余数量
        int mod = len % k;
        
        int[] lensSplited = new int[k];
        for(int i =0; i < k; i++){
            lensSplited[i] = 0;
        }
        int i = 0;
        // 判断链表是否足够长,用于划分
        if(k > len){// 不够长
            while(i < len){
                lensSplited[i] = lenSplited; 
                i++;
            }
            return split(head, len, lensSplited, k);
        }else{// 够长
            while(i < k){
                lensSplited[i] = lenSplited + ((mod-- > 0)? 1 : 0);
                i++;
            }
            return split(head, len, lensSplited, k);
        }
    }

    // 分割链表为指定数量指定长度
    private ListNode[] split(ListNode head, int len, int[] lensSplited, int k){
        ListNode[] array = new ListNode[k];
        ListNode temp;
        // 初始值设为null
        for(int i = 0; i < k; i++){
            array[i] = null;
        }

        int listNum = 0;
        while(listNum < k && head != null){
            array[listNum] = head;
            int l = 1;
            while(l < lensSplited[listNum]){
                head = head.next;
                l++;
            }
            if(head != null){
                temp = head.next;
                head.next = null;
                head = temp;
            }
            listNum++;
        }
        return array;
    }
}

注意事项

  • 1.java不能对数组整体赋值吗?必须要用循环?

拓展延伸

  • 注意分析题目中的数学关系。

这个更简洁。

class Solution {
    public ListNode[] splitListToParts(ListNode head, int k) {
    int N = 0;
    ListNode cur = head;
    while (cur != null) {
        N++;
        cur = cur.next;
    }
    int mod = N % k;
    int size = N / k;
    ListNode[] ret = new ListNode[k];
    cur = head;
    for (int i = 0; cur != null && i < k; i++) {
        ret[i] = cur;
        int curSize = size + (mod-- > 0 ? 1 : 0);
        for (int j = 0; j < curSize - 1; j++) {
            cur = cur.next;
        }
        ListNode next = cur.next;
        cur.next = null;
        cur = next;
    }
    return ret;
    }
}

10 328. 奇偶链表

题目

思路描述

  • 这有什么难的?计数,区分奇偶,尾插法。
  • 不好意思,题理解错了。
  • 双指针,一个指奇节点一个指偶节点,新建两个头指针作为划分后的奇偶链表的头节点。

代码实现
java代码:

class Solution {
    public ListNode oddEvenList(ListNode head) {
        // 预处理
        if(head == null || head.next == null || head.next.next == null){
            return head;
        }

        // 头结点
        ListNode oddHead = head, evenHead = head.next;
        ListNode oddNode = evenHead.next, evenNode = oddNode.next, oddTail = oddHead, evenTail = evenHead;

        // 遍历区分奇偶节点
        while(oddNode != null && evenNode != null){
            // 尾插法奇链表
            oddTail.next = oddNode;
            oddTail = oddNode;
            oddNode = oddNode.next;
            if(oddNode != null){
                oddNode = oddNode.next;
            }else{
                break;
            }

            // 尾插法偶链表
            evenTail.next = evenNode;
            evenTail = evenNode;
            evenNode = evenNode.next;
            if(evenNode != null){
                evenNode = evenNode.next;
            }else{
                break;
            }
        }

        // 偶链表链到奇链表后
        if(oddNode == null){
            oddTail.next = evenHead;
            evenTail.next = null;
        }else{
            oddTail.next = oddNode;
            oddTail = oddNode;
            oddTail.next = evenHead;
            evenTail.next = null;
        }

        return oddHead;
    }
}

java代码:

class Solution {
    public ListNode oddEvenList(ListNode head) {
        // 预处理
        if(head == null || head.next == null || head.next.next == null){
            return head;
        }

        // 
        ListNode evenHead = head.next, oddNode = head, evenNode = head.next;
        while(evenNode != null && evenNode.next != null){
            oddNode.next = oddNode.next.next;
            oddNode = oddNode.next;

            evenNode.next = evenNode.next.next;
            evenNode = evenNode.next;
        }

        // 偶链表接到奇链表后面
        oddNode.next = evenHead;
        return head;
    }
}

注意事项

  • 注意事项

拓展延伸

  • 拓展延伸

11 剑指 Offer 35. 复杂链表的复制

题目

思路描述

  1. 都在注释里了,我的方法很暴力.
  2. 虽然random指向是随机的,但是指向的节点在链表中的位置是一定的,所以我们可以通过得到每个节点的序号,来找到每个节点对应的random指向。
  3. 我现在的方法是遍历链表找序号对应的节点,有没有什么办法能够将遍历的过程省去呢?得到一个节点直接能够知道他的位置。
  4. 时空复杂度:O(n2) O(1)

代码实现
java代码:

class Solution {
    public Node copyRandomList(Node head) {
        // 先按照普通的链表进行复制,random指针先赋值为null
        Node newH = new Node(-1001); // 头指针尾指针复制链表
        Node tail = new Node(-1001);
        Node originalHead = head;
        newH = tail;
        int len = 0; // 获取链表的长度
        while (head != null) { // 仅复制next节点
            Node tmp = new Node(-1001);
            tmp.val = head.val;
            tmp.next = head.next;
            // tail.random = null; // 初始化的tail的random本身就是空

            head = head.next;
            tail.next = tmp;
            tail = tmp;
            len++;
        }
        tail.next = null; // 尾节点置空

        head = originalHead; // 原始链表的头,用于遍历
        Node copyListHead = newH.next; // 复制链表的头
        Node nowProcess = copyListHead; // 当前正在处理的复制链表中的节点
        Node tmpHead = new Node(-1001); // 复制链表的头,用于遍历复制链表,寻找对应的random节点
        int copyIdx;
        while (head != null) {
            // 首先找到当前head节点指向的random节点是链表中的倒数第几个
            // 倒数第零个表示null
            int idx= 0; // 计数
            Node randNode = head.random;
            while (randNode != null) {
                idx++; 
                randNode = randNode.next;
            }

            // 同样找到在copyList中对应的倒数那个
            
            // 这里可以优化一下
            copyIdx = len;
            tmpHead = copyListHead;
            while (copyIdx != idx) {
                tmpHead = tmpHead.next;
                copyIdx--;
            }
            nowProcess.random = tmpHead;

            head = head.next;
            nowProcess = nowProcess.next;
        }

        return newH.next;
    }
}

思路描述

  1. 将原始链表进行拆分复制,接在原始链表中每一个对应节点的后面。
    在这里插入图片描述
    在这里插入图片描述
  2. 根据原始节点的random指向,获取到新复制出的节点,并修改复制出的节点的random指针。
    在这里插入图片描述
  3. 恢复原始链表的next指向,修改复制链表的next指向。
    在这里插入图片描述
  4. 时空复杂度:O(3n) O(1)
  5. 必须要三个循环才可以,官方题解说的“读者们也可以自行尝试在计算拷贝节点的随机指针的同时计算其后继指针,这样只需要遍历两次。”,即使像这样做了,还是要一个循环来复原原始链表的next指向,如果修改原始next指针和修改拷贝节点的next指针同时进行的话,可能会导致拷贝节点的random指针指向了原始节点中的值,这样就不符合题意了。
class Solution {
    public Node copyRandomList(Node head) {
        // 1 -> 2 -> 3 -> 4
        // 1 -> 1 -> 2 -> 2 -> 3 -> 3 -> 4 -> 4
        if (head == null) return head; // 特殊情况

        Node node = head;
        while (node != null) { // 将原始链表复制一份,并穿插在原始链表中,每两个相同的相邻接点中第二个是新节点,未来用于返回
            Node newNode = new Node(node.val); // 新建节点
            newNode.next = node.next; // 复制next关系
            node.next = newNode; // 接在原始节点后面
            node = newNode.next; // 遍历
        }
        
        Node tmpHead = head;
        while (tmpHead != null) {
            node = tmpHead.next;
            node.random = tmpHead.random == null ? null : tmpHead.random.next; // 查找random节点,并赋值给copy出来的链表
            tmpHead = tmpHead.next.next;
        }

        // 将原始链表的next关系复原,并修改所复制链表的next关系。
        tmpHead = head;
        Node copyHead = head.next;
        while (tmpHead != null) {
            node = tmpHead.next;
            tmpHead.next = tmpHead.next.next; // 原始链表next复原
            node.next = node.next == null ? null : node.next.next; // 复制链表的next关系复原
            tmpHead = tmpHead.next; // 遍历
        }

        return copyHead;
    }
}

注意事项

  1. 注意事项

拓展延伸

  1. 拓展延伸

12 25. K 个一组翻转链表

题目

思路描述

  1. 题不难,但是有好多小细节,而且自己的思路有点不完善,导致最终写出的代码有点ugly。
  2. 时空复杂度:O(n) O(1)

代码实现

class Solution {
    int len;
    
    public ListNode reverseKGroup(ListNode head, int k) {
        // 统计长度 + 翻转链表
        if (head.next == null) return head; // 特殊情况

        ListNode h = new ListNode();
        ListNode tail = new ListNode();
        h.next = null;
        tail = null;

        ListNode[] headTail = new ListNode[2];
        ListNode[] twoHead = new ListNode[2];
        do {
            len = k;
            twoHead = countLength(head);
            headTail = reverseLinkList(twoHead[0], twoHead[1]);

            if (h.next == null) {
                h.next = headTail[0];
            }
            if (tail == null) {
                tail = headTail[1];
            } else {
                tail.next = headTail[0];
                tail = headTail[1];
            }

            head = twoHead[1];
        } while(head != null);

        return h.next;
    }

    private ListNode[] countLength(ListNode head) {
        ListNode[] twoHead = new ListNode[2];
        twoHead[0] = head;
        while (len-- != 0 && head != null) {
            head = head.next;
        }
        twoHead[1] = head;

        return twoHead;
    }

    private ListNode[] reverseLinkList(ListNode head, ListNode nextHead) {
        if (nextHead == null && len != -1) { // 剩余长度不够的情况
            return new ListNode[]{head, null};
        }
        // 翻转链表
        ListNode h = new ListNode();
        ListNode tail = new ListNode();
        h.next = null;
        tail = null;
        ListNode tmp = new ListNode();
        while (head != nextHead) {
            tmp = head;
            head = head.next;
            tmp.next = h.next;
            h.next = tmp;

            if (tail == null) {
                tail = tmp;
            }
        }
        tail.next = nextHead;

        return new ListNode[]{h.next, tail};
    }
}

注意事项

  1. 注意事项

拓展延伸

  1. 官方写的就很不错
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode hair = new ListNode(0); // 指向head的“头发”结点,头之前是头发23333
        hair.next = head;
        ListNode pre = hair;

        while (head != null) {
            ListNode tail = pre;
            // 查看剩余部分长度是否大于等于 k
            for (int i = 0; i < k; ++i) {
                tail = tail.next;
                if (tail == null) { // 如果此时剩下的节点个数不够k个,那么就可以直接返回了
                    return hair.next;
                }
            }
            ListNode nex = tail.next; // 找到了要反转的这一段的尾节点,并且求出下一段的头节点
            ListNode[] reverse = myReverse(head, tail); // 将目前head 到 tail这一段进行反转
            head = reverse[0]; // 反转后的头
            tail = reverse[1]; // 反转后的尾
            // 把子链表重新接回原链表
            pre.next = head;
            tail.next = nex;

            // 更新头发和头指针,进行下一段的反转工作
            pre = tail;
            head = nex;
        }

        return hair.next;
    }

    public ListNode[] myReverse(ListNode head, ListNode tail) { // 反转具体的一段链表
        ListNode prev = tail.next; // 先求出到哪里终止反转,tail的next
        ListNode p = head; // 
        while (prev != tail) { // 这个反转的方式有点妙啊
            ListNode nex = p.next; // 
            p.next = prev; // 
            prev = p;
            p = nex;
        }
        
        return new ListNode[]{tail, head};
    }
}

13 92. 反转链表 II

题目

思路描述

  1. 时空复杂度:O(n) O(1)

代码实现

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        if (head == null || head.next == null) {
            return head;
        }
        if (left >= right) {
            return head;
        }

        ListNode h = new ListNode();
        h.next = head;
        ListNode lTail, mHead, mTail, rHead;
        mHead = h;
        while (left != 1) {
            mHead = mHead.next;
            left--;
            right--;
        }
        lTail = mHead; // 被截断后的左侧链表的尾节点
        mHead = mHead.next; // 中间这一段的head
        mTail = mHead;
        while (right != 1) {
            mTail = mTail.next;
            right--;
        }
        rHead = mTail.next; // 被截断后的右侧链表的head
        mTail.next = null; // 截断中间这一段链表
        
        ListNode[] headAndTail = new ListNode[2];
        headAndTail = reverse(mHead); // 反转中间链表
        lTail.next = headAndTail[0];
        headAndTail[1].next = rHead;

        return h.next;
    }

    private ListNode[] reverse(ListNode head) { // 反转链表
        ListNode h = new ListNode();
        h.next = null;
        ListNode tmp, tail = head;
        while (head != null) {
            tmp = head;
            head = head.next;
            tmp.next = h.next;
            h.next = tmp;
        }

        return new ListNode[]{h.next, tail};
    }
}

注意事项

  1. 注意事项

拓展延伸

  1. 官

14 143. 重排链表

题目

思路描述

  1. 时空复杂度:O(n) O(1)

代码实现

// 链表取中 + 反转 + 交错链接
class Solution {
    public void reorderList(ListNode head) {
        // 先找中间,分成两段
        // 后面反转
        // 交错链接
        if (head == null || head.next == null) {
            return;
        }

        ListNode fast = head.next, slow = head; // 注意快指针一定要先后置一个
        while (fast != null && fast.next != null) { // 链表取中一定要这样写!!!
            slow = slow.next;
            fast = fast.next.next;
        }

        ListNode head2 = slow.next;
        slow.next = null;

        head2 = reverse(head2);
        ListNode tmp1;
        while (head2 != null) {
            tmp1 = head;
            head = head.next;
            tmp1.next = head2;

            tmp1 = head2;
            head2 = head2.next;
            tmp1.next = head;
        }

        return;
    }

    private ListNode reverse(ListNode head) {
        ListNode hair = new ListNode();
        hair.next = null; // 今天链表反转都写错了
        ListNode tmp;
        while (head != null) {
            tmp = head;
            head = head.next;
            tmp.next = hair.next;
            hair.next = tmp;
        }

        return hair.next;
    }
}

注意事项

  1. 链表取中、取三分之一时,的确使用快慢指针,但是一定要提前判断在进入这次循环前,快指针还能不能走完下一次快走的步数
		// 取中
        ListNode fast = head.next, slow = head; // 注意快指针一定要先后置一个
        while (fast != null && fast.next != null) { // 链表取中一定要这样写!!!
            slow = slow.next;
            fast = fast.next.next;
        }
        // 取三分之一
        ListNode fast = head.next, slow = head; // 注意快指针一定要先后置一个
        while (fast != null && fast.next != null && fast.next.next != null) { // 一定要这样写!!!
            slow = slow.next;
            fast = fast.next.next.next;
        }

拓展延伸

  1. 官

15 23. 合并K个升序链表

题目

思路描述

  • 时空复杂度O(knlogk), O(logk)
    在这里插入图片描述

代码实现

// 归并 时空复杂度O(knlogk), O(logk)
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        int n = lists.length;
        if (n == 0) return null;
        if (n == 1) return lists[0]; // 特殊情况处理

        return merge(lists, 0, n - 1); // 划分子问题
    }

    private ListNode merge(ListNode[] lists, int l, int r) { // 切分子问题
        if (l > r) {
            return null; // 如果当前没有子问题可以切分,直接返回null
        }
        if (l == r) {
            return lists[l]; // 如果当前的区间中只有一个链表,直接返回这个链表
        }

        int mid = l + ((r - l) >> 1); // 区间中有多个链表,我们取中平分
        ListNode l1 = merge(lists, l, mid); // 递归的划分子问题
        ListNode l2 = merge(lists, mid + 1, r);

        return mergeSort(l1, l2); // 传统的归并过程
    }

    private ListNode mergeSort(ListNode l1, ListNode l2) {
        if (l1 == null || l2 == null) {
            return l1 == null ? l2 : l1;
        }

        ListNode hair = new ListNode();
        ListNode tail = hair;
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                tail.next = l1;
                l1 = l1.next;
            } else {
                tail.next = l2;
                l2 = l2.next;
            }
            tail = tail.next;
        }

        tail.next = l1 == null ? l2 : l1;

        return hair.next;
    }
}

在这里插入图片描述

// 优先队列,小顶堆 时空复杂度O(knlogk), O(k) 这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        int n = lists.length;
        if (n == 0) return null;
        
        PriorityQueue<ListNode> pq = new PriorityQueue<>(n, (a, b) -> (a.val - b.val)); // 自定义比较器
        for (int i = 0; i < n; i++) { // 第一次放入
            if (lists[i] != null) {
                pq.offer(lists[i]);
            }
        }
        ListNode hair = new ListNode();
        ListNode tail = hair;
        ListNode tmp;
        while (!pq.isEmpty()) {
            tmp = pq.poll();
            tail.next = tmp;
            tail = tail.next;
            if (tmp.next != null) {
                pq.offer(tmp.next);
            }
        }

        return hair.next;
    }
}

注意事项

  1. 链

拓展延伸

  1. 官

16 148. 排序链表

题目

思路描述

  1. 时空复杂度:O(nlogn) O(logn),基于数组的空间复杂度是O(n),但是这道题是链表,不需要额外的空间,是需要开辟递归栈,所以空间复杂度是O(logn).

代码实现

// 归并 时空复杂度:O(nlogn) O(logn)
class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) // 如果当前是空或者只有一个节点
            return head;

        ListNode fast = head.next, slow = head;
        while (fast != null && fast.next != null) { // 分割子问题
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode tmp = slow.next; // tmp右侧链表的头
        slow.next = null; // 分割链表

        ListNode left = sortList(head); // 左右两个区间
        ListNode right = sortList(tmp);

        ListNode hair = new ListNode(0); // 合并后的头
        ListNode tail = hair; // 尾插法
        while (left != null && right != null) { // 归并
            if (left.val < right.val) {
                tail.next = left;
                left = left.next;
            } else {
                tail.next = right;
                right = right.next;
            }
            tail = tail.next;
        }
        tail.next = left != null ? left : right;

        return hair.next;
    }
}
// 快排 时空复杂度O(nlogn)O(logn)
class Solution {
    public ListNode sortList(ListNode head) {
        return quickSort(head);
    }
    
    public ListNode quickSort(ListNode head) {
        if(head == null || head.next == null) return head; // 如果问题规模过小,直接返回

        ListNode slow = head, fast = head.next; // 快慢指针取中间节点
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        int val = slow.val; // 基准值

        ListNode h1 = new ListNode(); // 基准值左侧的链表头
        ListNode h2 = new ListNode(); // 基准值右侧的链表头
        ListNode h3 = new ListNode(); // 可能会有和基准值相同的节点,我们把他全部保留在这个头结点后面,这样我们可以减少接下来的子问题的规模
        ListNode t1 = h1, t2 = h2; // 基准值左侧和右侧的链表的尾指针,因为我们是要使用尾插法保证顺序
        ListNode t3 = h3; // 所有的基准值,为了保持一致,我们一样用尾插法构造链表
        ListNode cur = head; // 当前遍历到的元素
        
        while(cur != null) {
            ListNode next = cur.next; // 暂存下一个元素
            if(cur.val < val) { // 如果当前这个元素的大小小于基准值
                cur.next = t1.next; // 使用尾插法将当前这个节点链到基准值左侧的链表上
                t1.next = cur;
                t1 = t1.next;
            } else if(cur.val > val) { // 如果当前这个元素的大小大于基准值
                cur.next = t2.next; // 使用尾插法将当前这个节点链到基准值右侧的链表上
                t2.next = cur;
                t2 = t2.next;
            } else { // 相等的部分,留在这里,等着链接
                cur.next = t3.next;
                t3.next = cur;
                t3 = t3.next;
            }
            cur = next; // 遍历下一个元素
        }

        h1 = quickSort(h1.next); // 递归左侧链表,注意这里的h1已经不是原来的h1了。
        h2 = quickSort(h2.next); // 递归右侧链表

        h3 = h3.next;
        t3.next = h2; // 基准值链表链接右侧较大部分链表
        if(h1 == null) { // 如果左侧链表为空,直接返回基准值以及基准值之后的元素
            return h3;
        } else { // 否则,我们需要找到左侧传回链表的尾部,因为原来左侧只是经过了划分,而没有排序,排完序后我们需要重新寻找它的尾节点
            t1 = h1; // 寻找尾节点
            while(t1.next != null) {
                t1 = t1.next;
            }
            t1.next = h3; // 链接上基准值和基准值右侧的节点
            return h1;
        }
    }
}

注意事项

  1. 链

拓展延伸

  1. 官

17 146. LRU 缓存

题目

思路描述

  1. 时空复杂度:

代码实现

public class LRUCache {
    // 定义内部类,
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
        public DLinkedNode() {}
        public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
    }

    // 定义成员变量
    private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>(); // hashmap用于get
    private int size; // 当前大小
    private int capacity; // 容量上限
    private DLinkedNode head, tail; // 双向链表的头尾指针

    public LRUCache(int capacity) { // 初始化
        this.size = 0; // 初始容量为零
        this.capacity = capacity; // 容量上限

        // 使用伪头部和伪尾部节点
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail; // 初始化指向
        tail.prev = head;
    }

    public int get(int key) { // get 方法
        DLinkedNode node = cache.get(key); // 先获取这个节点
        if (node == null) { // 不存在的话返回 -1
            return -1;
        }
        moveToHead(node); // 如果 key 存在,先通过哈希表定位,再移到头部
        
        return node.value;
    }

    public void put(int key, int value) {
        DLinkedNode node = cache.get(key); // 通过hashmap获取对应节点
        if (node == null) {
            DLinkedNode newNode = new DLinkedNode(key, value); // 如果 key 不存在,创建一个新的节点
            cache.put(key, newNode); // 添加进哈希表
            addToHead(newNode); // 添加一个新节点至双向链表的头部
            ++size; // 当前容量++
            if (size > capacity) { // 如果超出容量,删除双向链表的尾部节点
                DLinkedNode tail = removeTail();
                cache.remove(tail.key); // 删除哈希表中对应的项
                --size; // 容量--
            }
        } else {
            node.value = value; // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
            moveToHead(node); // 移动旧有节点到队头
        }
    }

    // 双向链表的操作
    private void addToHead(DLinkedNode node) { // 新添加进来的节点放到队头
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(DLinkedNode node) { // 删除一个节点
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void moveToHead(DLinkedNode node) { // 移动一个已存在的节点到队头,相当于把这个节点从原来的双向链表中删除,再新建一个节点到队头
        removeNode(node);
        addToHead(node);
    }

    private DLinkedNode removeTail() { // 删除最久没有使用的节点
        DLinkedNode res = tail.prev; // 先获取队尾的节点
        removeNode(res); // 删除这个节点
        return res; // 返回被删除的节点,用于将hashmap中的节点一并删除
    }
}

注意事项

  1. 链

拓展延伸

  1. 官
鼎捷T100二次开发实战:如何给开窗功能加上权限锁(附完整代码) 本文详细解析了鼎捷T100二次开发中开窗功能权限锁的实现方法,提供了两种技术方案:开窗程序重构法和动态WHERE条件注入法,并附上完整代码示例。通过真实案例,帮助开发者解决数据权限细粒度控制的难题,提升ERP系统的安全性和实用性。 阅读详情

相关推荐

手把手教你修改miniwiggler配置信息,解决UDE连接问题(附FT_PROG工具下载)

本文详细介绍了如何使用FT_PROG工具修改miniwiggler配置信息,解决UDE连接问题。通过分析FT2232芯片的EEPROM结构,提供从驱动安装到配置烧写的完整流程,帮助开发者实现无缝连接英飞凌TriBoard开发板。文章还包含常见错误解决方案和高级批量配置技巧。

weixin_30919429的博客 373

东华大学2020考研计算机复试准备上机题解析答案_进阶篇(31-60)

文章目录前言31 最高频率 前言 提交代码: 选择C++编程语言,因为有的时候会用到C++的一些方便的头文件什么的,还有我编写代码是有一部分是纯C的,因为做题来讲C的scanf和printf很方便。 发布文章安排: 我会抽时间发文章的,看时间安排了,现在时间有点紧吧。马上过年了。过完年要开始准备准备其他东西了 解题解法质量: 关于我的解法和代码的精简程度,我是以当时做题的心态来解题的,由于当时急着...

zhou_hao_ran的博客 5392

芋道前后端分离项目跳过登录

在此页面中可以看到当在没有获取到token时,如果此页面在白名单中则直接进入,所以我们将刚刚配置在。在此路径下配置需要跳过登录的页面路径,记住path中编辑的名称。根据以上两图可以发现芋道的。将所有需要跳过登录的方法。,否则会提示登录状态过期。至此完成免登录进入页面。

FanZaiYo的博客 5485

【Leetcode学习笔记】链表

【Leetcode学习笔记】链表

weixin_42685184的博客 564

STM32F407通过SMBus协议精准读取BQ40Z50电池电量

本文详细介绍了STM32F407通过SMBus协议精准读取BQ40Z50电池电量的实现方法。从硬件连接到软件驱动开发,再到通信异常排查,提供了完整的解决方案。重点解析了SMBus协议的特殊时序要求、GPIO模拟驱动的关键代码,以及实际调试中的常见问题与对策,帮助开发者高效完成电池管理系统开发。

weixin_29189003的博客 251

Upwork入门指南:如何创建吸引人的个人资料

本文详细介绍了如何在Upwork上创建并优化个人资料,帮助自由职业者吸引更多客户。内容包括: 注册与验证:从注册账号到邮箱验证的完整步骤。 个人资料填写:如何撰写吸引人的标题、简介,选择技能标签,以及设置专业头像和费率。 作品集与优化:上传高质量作品集,提升搜索排名和客户信任度。 常见问题解答:解决新手常见问题,如无工作经验或审核不通过。 通过本文的指导,你将学会打造一个专业且高效的个人资料,为在Upwork上获得更多机会奠定基础。

qq_61813593的博客 3513

Leetcode——链表

Leetcode——链表合并两个有序链表删除排序链表中的重复元素环形链表相交链表移除链表元素反转链表回文链表删除链表中的节点 链表(Linked List)是最简单的线性的、动态数据结构。理解它是理解树结构、图结构的基础。 区别于数组,链表中的元素不是存储在内存中连续的一片区域,链表中的数据存储在每一个称之为「结点」复合区域里,在每一个结点除了存储数据以外,还保存了到下一个节点的指针(Pointer)。 由于不必按顺序存储,链表在插入数据的时候可以达到 O(1)O(1) 的复杂度,但是查找一个节点或者访问特

weixin_48367136的博客 1464

【异常】Claude Code 在 Windows CMD 中出现重影现象的排查与解决

Windows CMD运行Claude Code时出现文字重影、乱码等问题,原因是传统CMD对现代ANSI终端控制序列支持不足。解决方案包括:1)推荐安装Windows Terminal(完全支持ANSI标准);2)使用PowerShell 7;3)优化CMD设置(启用虚拟终端、UTF-8编码);4)关闭Claude Code视觉特效。建议优先使用Windows Terminal以获得最佳体验,这是最彻底的解决方案。其他方案仅能部分改善或缓解问题。

奶爸的编程之路,也就一周冷个三天 1958

Leetcode题解——数据结构之链表

1. 找出两个链表的交点 2. 链表反转 3. 归并两个有序的链表 4. 从有序链表中删除重复节点 5. 删除链表的倒数第 n 个节点 6. 交换链表中的相邻结点 7. 链表求和 8. 回文链表 9. 分隔链表 10. 链表元素按奇偶聚集 链表是空节点,或者有一个值和一个指向下一个链表的指针,因此很多链表问题可以用递归来处理。 1. 找出两个链表的交点 1...

dieshi8689的博客 812

顶刊论文引言用AI怎么写?借助Gemini 3 Pro结合四段式写出逻辑清晰的Introduction

写研究目标时,先明确研究问题,直接回应前文提到的研究缺口,如 “This study aims to investigate whether X modulates Y via the Z pathway in human cells.”然后再提出你的研究假设,当理论依据清晰时,可以用如 “We hypothesized that inhibiting X would rescue Y deficiency in this model.”的句子点出研究目标。要求:1)明确陈述本研究拟解决的核心科学问题;

智能AI让学术科研更容易 180

3、图像中文字信息提取技术全解析

本文全面解析了图像中文字信息提取(Text Information Extraction,TIE)的技术原理、挑战及应用领域。详细介绍了图像中三种主要文字形式:场景文字、字幕文字和文档文字的特点及提取难点。系统阐述了TIE技术的主要流程步骤,包括文字检测、定位、提取与增强、识别等关键阶段,并对主流技术方法进行了分类比较,包括基于连通组件、边缘、纹理等方法的优缺点分析。文章还介绍了多种其他提取技术,如二值化方法、混合方法、基于梯度的方法等,并提出了一种基于立体帧的新型场景文字提取方法,通过实验验证了该方法在召

ll5678的博客 119

LeetCode中的数据结构2:链表

链表问题要尤其注意,检查边界条件是否考虑全面,代码在边界条件下是否能正确运行,如:链表为空、链表只包含一个结点、链表只包含两个结点、代码逻辑处理头结点和尾结点时,能否正常执行。

铁马秋风大散关 288

【Claude】权限被拒绝 (Permission Denied) 全场景排查 — 已解决

权限配置是 Claude Code 安全使用的核心机制。通过合理的 allow/deny 规则、正确的通配符使用、子代理独立配置、定期安全审计,可以在保证安全性的同时不影响开发效率。deny 优先:deny 规则优先级高于 allow,先保护敏感资源通配符精确单层匹配,**递归匹配,Bash(cmd*)允许带参数最小权限:只允许必要的操作,避免Bash(*)等危险规则CI 用 skip:Headless 模式用避免挂起子代理独立:每个子代理单独配置权限,不自动继承保护密钥:deny.env。

一键难忘的博客 3935

数据结构——线性表(链表,力扣中等篇,技巧型)

当链表无序时,去重操作无法像有序链表那样通过简单比较相邻节点来完成,需要借助额外的数据结构来记录已出现过的值。因为链表是排序的,重复元素一定相邻,所以只需比较当前节点和下一个节点的值。思路就是创建两个临时链表,分别存储小于 x 的节点和大于或等于 x 的节点,最后将这两个链表连接起来,保持原有节点的相对顺序。思路2:先将链表连成环,再找到新的头节点位置并断开环,从而完成旋转操作。思路1:将链表分成两个小链表,然后将两个链表交换位置,重新连接即可。不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

2303_77489296的博客 2338

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Leetcode刷题记录——链表篇

本文是一些leetcode链表刷题笔记,都是暴力方法,还未优化,为了快速能够先通过题目,之后再考虑如何A,希望能给大家带来点启发。

shineber的博客 2172

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

LeetCode——链表篇

LeetCode——链表篇一、移除链表元素题解代码二、反转链表题解代码三、两两交换链表中的节点题解代码四、删除链表的倒数第 N 个结点题解代码五、相交链表题解代码六、环形链表题解代码七、环形链表 ||题解代码 一、移除链表元素 题解 该题其实就只需要遍历一下链表,需要注意的是,做这种题目的时候,最好新建一个头结点,否则在执行删除操作的时候难以进行。删除操作是链表中最基本的操作,需要熟练掌握。 代码 # Definition for singly-linked list. # class ListNode:

Pcl2001的博客 1894

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

力扣刷题记录

Leecode

Mr_Liuss的博客 2636

[每日一练] 移除链表元素 - 力扣(LeetCode)

​ 🍹欢迎各路大佬来到 Nick 主页指点 ☀️本期文章将学习 [每日一练] 移除链表元素 - 力扣(LeetCode),我是博主Nick。✨ ✨我的博客主页:Nick_Bears 🌹꧔ꦿ 🌹꧔ꦿ博文内容如对您有所帮助,还请给个点赞 + 关注 + 收藏✨ ​

Nick 的笔记 798

【反转链表系列】力扣206,92,25

本文涉及的力扣题目,涉及简单、中等、困难三个难度力扣206.反转链表力扣92.反转链表 II力扣25.K 个一组翻转链表反转链表这类型的题目,折磨了挺久,经常弄懂了一道题,但是遇到下一道反转链表的题目还是不会。所以我整理了三道比较经典的反转链表的题目,从浅到深一步一步领悟反转链表的处理思路。

沉迷写代码的程序猿的博客 1147

408系列二:数据结构&&力扣必做题

接上篇博客记录的408整体介绍,从这一篇博客开始,我将详细介绍408每个科目的具体备考策略。初步介绍一些关于数据结构的基础知识,主要介绍的是算法方面,希望可以帮助你~

weixin_73995703的博客 1193

力扣刷题记录:

int val;// 节点上存储的元素// 指向下一个节点的指针ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数//结点的值int val;//下一个结点//无参构造函数//节点的构造函数//节点的构造函数什么是链表,链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。203. 移除链表元素。

2504_91017195的博客 1517

力扣OJ题感悟——链表篇

1.移除链表元素 代码如下: /** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeElements(struct ListNode* head, int val) ...

New_learner55的博客 470

数据结构之线性表——LeetCode:707. 设计链表,206. 反转链表,92. 反转链表 II

模拟了一个链表数据结构,提供了初始化链表、获取特定位置节点值、在头部插入节点、在尾部插入节点、在特定位置插入节点以及删除特定位置节点等功能。设置为 0,表示链表中没有实际节点,同时创建一个虚拟头节点。次(因为虚拟头节点不算实际节点),找到目标节点并返回其值。以指示链表中的上一个节点。,即反转当前节点的指针方向,使其指向前一个节点。,即将当前节点变为反转后的链表中的新的末尾节点。的下一个节点,保存链表的后续部分。,实现在链表尾部插入节点的功能,因为当在长度为。的位置插入节点时,相当于在链表末尾追加节点。

u014114223的博客 932

【数据结构与算法 | 灵神题单 | 遍历链表篇】力扣1290, 2058

用栈来记录链表的元素,由于栈的性质,最先弹栈的元素是末位,转换成10进制需要*1,其次弹栈的元素转换成10进制需要*2...直到栈空,将所有的值加起来返回。,2,2,3,2,2,2,7]:第二个节点是一个局部极大值点,因为 3 比 1 和 2 大。,2,5,1,2]:第三个节点是一个局部极小值点,因为 1 比 3 和 2 小。,2,2,2,7]:第五个节点是一个局部极大值点,因为 3 比 2 和 2 大。,1,2]:第五个节点是一个局部极大值点,因为 5 比 2 和 1 大。如果临界点少于两个,则返回。

2301_80912559的博客 975

【数据结构】(牛客)链表的回文结构,LeetCode相交链表,LeetCode环形链表

本文详细讲述了(牛客)链表的回文结构,LeetCode相交链表,LeetCode环形链表等题目,里面讲述了我自己的思路,并将做题思路转化成动图展现出来,有助于更好地理解。

m0_63198468的博客 1385

力扣---链表1

本博客用于力扣链表系列的刷题记录,跟的是代码随想录的顺序,在刷完之后,最后对链表相关的博客做规整和总结,同之前的数组。

2301_78138281的博客 749
上一篇: 目标检测算法
下一篇: Hadoop学习笔记
LencyGe
博客等级 码龄7年 26粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值