数据结构专项-算法第一周(链表下)

113 阅读2分钟
  1. 25. K 个一组翻转链表
  2. 83. 删除排序链表中的重复元素
  3. 82. 删除排序链表中的重复元素 II
  4. 19. 删除链表的倒数第 N 个结点
  5. 24. 两两交换链表中的节点
  6. 61. 旋转链表

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

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

提示: 链表中节点的数目在范围 [0, 100] 内 0 <= Node.val <= 100

题意理解: 两两交换列表中的节点(使用循环遍历即可)

  1. 需要设置一个新的头结点newHead,方便交换,newHead.next指向head
  2. 遍历条件及后面存在两个以上节点
  3. 声明变量,一个存第一个值,一个存第三值
  4. 头指针指向第二个节点,第一个节点执行第三个值
  5. 第二个节点指向第一个,头结点等于等二个节点
  6. 返回newHead.next
var swapPairs = function(head) {
    const newHead = new ListNode(-1);
    newHead.next = head;
    let currentNode = newHead;
    while(currentNode.next && currentNode.next.next){
        let tail = currentNode.next.next.next;
        let current= currentNode.next; 
        currentNode.next = currentNode.next.next;
        current.next = tail;
        currentNode.next.next = current;
        currentNode = currentNode.next.next;
    }
    return newHead.next;
};

25. K 个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 k 是一个正整数,它的值小于或等于链表的长度。 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序

提示: 列表中节点的数量在范围 sz 内 1 <= sz <= 5000 0 <= Node.val <= 1000 1 <= k <= sz

题意理解,没k个节点反转一次

  1. 需要设置一个新的头结点newHead,方便交换,newHead.next指向head
  2. 声明变量pre = newHead,进行N个k的循环
  3. tail = pre用来判断时候够k个数(可以反转),如果不够返回newHead.next
  4. nex保存第N个循环的头结点
  5. 第n个进行反转reverse,返回反转后的头结点和未反转的头结点
  6. 反转后节点重新指向,头结点指向为反转的头结点
  7. 反转函数循环过程(举例:第一次[1,2,3,4],[1];第二次[2,3,4],[2,1];第三次[3,4],[3,2,1],...一次迭代直至为空)本例远离如此,只是循环条件不同
var reverseKGroup = function (head, k) {
    const newHead = new ListNode(-1);
    newHead.next = head;
    let pre = newHead;
    while (head) {
        let tail = pre;
        for (let i = 0; i < k; i++) {
            tail = tail.next
            if (!tail) {
                return newHead.next;
            }
        }
        let nex = tail.next;
        [head, tail] = reverse(head, tail);
        pre.next = head;
        tail.next = nex;
        pre = tail;
        head = tail.next;
    }
    function reverse(head, tail) {
        let prev = tail.next;
        let p = head;
        while (prev !== tail) {
            let nex = p.next;
            p.next = prev;
            prev = p;
            p = nex;
        }
        return [tail,head]
    }

    return newHead.next;
};

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

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

提示: 链表中节点数目在范围 [0, 300] 内 -100 <= Node.val <= 100 题目数据保证链表已经按升序 排列

题意理解: 相当链表去重重复的值(快慢指针原理)

  1. 遍历链表,判断当前节点和后一个节点的值是否相同
  2. 相同,当前节点指向后一个节点
  3. 否则就等于当前节点
var deleteDuplicates = function (head) {
    if(!head) return null;
    let fast = head;
    while(fast.next){
        if(fast.val===fast.next.val){
            fast.next = fast.next.next;
        }else{
            fast=fast.next
        }
    }
    return head
};

82. 删除排序链表中的重复元素 II

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

提示: 链表中节点数目在范围 [0, 300] 内 -100 <= Node.val <= 100 题目数据保证链表已经按升序 排列

题意理解: 只保留列表中的值出现一次的节点 与快慢指针用法相同

  1. 需要设置一个新的头结点newHead,方便交换,newHead.next指向head
  2. 然后判断下一个节点的值和下下一个节点的值是否相同,相同则内部再循环遍历(下个节点指向下下个节点)
  3. 否则当前节点=下个节点,循序安遍历
  4. 返回 newHead.next
var deleteDuplicates = function (head) {
    const newHead = new ListNode(-1);
    newHead.next = head;
    let slow = newHead;
    while (slow.next) {
        if (slow.next.next && slow.next.val === slow.next.next.val) {
            while(slow.next.next && slow.next.next.val === slow.next.val){
                slow.next=slow.next.next;
            }
            slow.next=slow.next.next
        } else {
            slow = slow.next;
        }
    }
    return newHead.next;
};

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

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

提示:

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

题意理解: 删除链表倒数第n个节点 提示给出n一定存在

  1. 需要设置一个新的头结点newHead,方便交换,newHead.next指向head
  2. 声明变量hand用来保存N的节点,currentNode=newHead保存慢节点
  3. 循环hand,hand走一步,currentNode走一步,放hand为空时,currentNode的下个节点就是被删除的节点(即currentNode.next=currentNode.next.next)
  4. 返回newHead.next
var removeNthFromEnd = function(head, n) {
    const newHead=new ListNode(-1);
    newHead.next = head;
    let currentNode = newHead
    let hand = currentNode.next;
    while(n--){
        hand = hand.next
    }
    while(hand){
        hand=hand.next;
        currentNode = currentNode.next;
    }
    currentNode.next=currentNode.next.next;
    return newHead.next;
};

61. 旋转链表

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

提示: 链表中节点的数目在范围 [0, 500] 内 -100 <= Node.val <= 100 0 <= k <= 2 * 109

题意理解: 旋转链表,将链表每个节点向右移动 k 个位置。

  1. 遍历节点计算节点长度len,对节点求余避免不必要的遍历
  2. 将链表改为循环列表
  3. len - 余数,就是循环链表要阶段的节点,截断
  4. 返回head
var rotateRight = function (head, k) {
    if (!head) return null;
    let len = 1;
    let p = head;
    while (p.next) {
        p = p.next;
        len++;
    }
    let index = len - k % len;
    // p.next = head;
    let cp = head;
    let cp1 = cp;
    while (index--) {
        cp = cp.next;
    }
    head=cp.next;
    cp.next = null;
    head = p.next;
    p.next = null;
    return head
};