为了账号安全,请及时绑定邮箱和手机立即绑定

玩转算法面试之链表

206 Reverse Linked List

图片描述

  • 反转链表。
  • 一般遇到这种题,入门的大概思路是利用栈存储,然后再反向弹出赋值更新(改变链表中的值),不过这种思路是错误的。
  • 那我先把头结点指向Null? 错,因为这样我们就拿不到2这个节点了。
  • 图片描述
  • 我们需要三个指针来帮我们解决问题。(pre,cur,next)三个节点依次向前移动
  • 图片描述
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let pre = null
    while (head) {
        // 保存下一个结点
        next = head.next
        // 反转指针方向
        head.next = pre
        // 节点递增
        pre = head
        head = next
    }
    return pre
};

92. Reverse Linked List II

反转一个链表从m到n的元素。
如对于链表1->2->3->4->5->NULL,m=2,n=4。则返回链表1->4->3->2->5->NULL

  • m和n超过链表范围怎么办? m和n是负值怎么办?
  • m>n怎么办?
  • m=1.或者n是最后一个
var reverseBetween = function(head, m, n) {
    if(m >= n) {
        return head;
    }
    
    var dummy = new ListNode(0);  //通过构建listNode,处理m==1的情况
    dummy.next = head;
    head = dummy;
    
    // 移动head到m-1的node;
    for(var i = 0; i < m - 1; i++) {
        head = head.next;
    }
    
    var pre = head.next;
    var cur = pre.next;
    
    for(i = 0; i < n - m; i++) {
        var tmp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = tmp;
    }
    
    // head.next仍然指向m节点
    head.next.next = cur;
    head.next = pre;
    
    return dummy.next; 
};

83. Remove Duplicates from Sorted List

给出一个有序链表,删除其中所有重复元素,使得每个元素只保留一次。

  • 如1->1->2,返回1->2
  • 如1->1->2->3->3,返回1->2->3

86. Partition List

给出一个链表以及一个数x,将链表重新整理,使得小于x的元素在前;大于等于x的元素在后。

  • 如1->4->3->2->5->2,×=3
  • 返回1->2->2->4->3->5
  • 左边和右边的顺序是任意还是需要保持原有链表的顺序

328. Odd Even Linked List

给出一个链表,将链表重新整理,使得所有索引为奇数的节点排在索引为偶数的节点前面。

  • 如1->2->3->4->5->NULL
  • 返回1->3->5->2->4->NULL
  • 第一个节点的索引为1
  • 奇数索引的节点和偶数索引的节点在重新整理后要保持相对顺序。

2. Add Two Numbers

给出两个非空链表,表示两个非负整数。其中每一个整数的各位数字以逆序存储,返回这两个整数相加所代表的链表。

  • 如342+465=807
  • 则给出2->4->3和5->6->4,返回7->0->8
  • 数字中是否有前置的零。(除零以外,没有前置零)
  • 当我们遇到字符串表示数字的情况时,要考虑负数。本文因为已经支持非负整数

445. Add Two Numbers II

给出两个非空链表,表示两个非负整数。其中每一个整数的各位数字以顺序存储,返回这两个整数相加所代表的链表。

  • 如342+465=807
  • 则给出3->4->2和4->6->5,返回8->0->7
  • 不允许修改输入的链表
  • 使用辅助数据结构

设立链表的虚拟头节点

203. Remove Linked List Elements

在链表中删除值为val的所有节点

  • 如1->2->6->3->4->5->6->NULL,要求删除值为6的节点
  • 返回1->2->3->4->5->NULL
    图片描述
  • 对删除第一个元素不适用,不过我们可以拿出来单独判断头节点,但是这样就产生了两个删除逻辑,所以这个时候就需要dummy虚拟节点,这样对链表中的所有节点都可以统一了
    图片描述
var removeElements = function(head, val) {
    if(head === null){
        return head;
    }
    
    var dummy = new ListNode(-1);
    dummy.next = head;
    prev = dummy;
    cur = head;
    
    while(prev !== null && prev.next !== null){
		// 如果当前元素等于要删除元素,删除
        if(cur.val === val) {
            prev.next = cur.next;
            cur = prev.next;
        } else {
            prev = cur;
            cur = cur.next;
        }
    }
    
    return dummy.next;
};

虚拟头节点技巧巩固

82. Remove Duplicates from Sorted Listed II

给定一个有序链表,将其中有重复的元素全部删除。

  • 如1->2->3->3->4->4->5,返回1->2->5
  • 如1->1->1->2->3,返回2->3

21. Merge Two Sorted Lists

merge两个有序的链表

24. Swap Nodes in Pairs

给定一个链表,对于每两个相邻的节点,交换其位置。

  • 如:链表为1->2->3->4->NULL
  • 返回:2->1->4->3->NULL
  • 只能对节点进行操作,不能修改节点的值
  • 下图next是不必要指针,但是去除优化效果不大

图片描述
图片描述

var swapPairs = function(head) {
    var dummy = new ListNode(0);
    dummy.next = head;
    var n1 = dummy;
    var n2 = head;
    // 确认还有节点可以交换
    while(n2 !== null && n2.next !== null){
        // 保存next节点,防止丢失
        var nextStart = n2.next.next;
        // 交换
        n1.next = n2.next;
        n1.next.next = n2;
        n2.next = nextStart;
        
        n1 = n2;
        n2 = n2.next;
    }
    
    return dummy.next;
};

25. Reverse Nodes in k-Group

给定一个链表,每k个节点为一组,反转每一组的k个节点。k为正整数且小于等于链表长度。如果链表长度不是k的整数倍,剩余部分不需要进行反转。如:1->2->3->4->5->NULL

  • 若k=2,则结果为:2->1->4->3->5->NULL
  • 若k=3,则结果为:3->2->1->4->5->NULL

147. Insertion Sort List

为一个链表进行插入排序

148. Sort List

写一个排序算法,用0(nlogn)的时间复杂度为一个链表进行排序
归并排序

237. Delete Node in a Linked List

给定链表中的一个节点,删除该节点
难点:不可能拿到删除节点的前一个节点
解决思路: deleteNode = deleteNode->next, 然后删除deleteNode->next(老办法)

var deleteNode = function(node) {
	if(node == null) return;

    if(node.next === null){
	    node.val = null;
        return;
    }
    
    node.val = node.next.val;
    node.next = node.next.next;
};

双指针技术

19. Remove Nth Node From End of List

给定一个链表,删除倒数第n个节点

  • 如:1->2->3->4->5->NULL,n=2
  • 返回:1->2->3->5
  • n从0计还是从1计
  • n不合法,负数或者大于链表长度如何处理(保证n合法)

解法1:先遍历一遍计算链表长度;再遍历一遍删除倒数第n个节点

  • 遍历两遍链表。能否只遍历一遍链表?
  • 借助两个指针: 两个指针间的距离相等

图片描述

var removeNthFromEnd = function(head, n) {
    var n1 = new ListNode();
    var n2 = new ListNode();
    var dummy = n2;
    
    n1.next = head;
    n2.next = head;
    // 这里判断n1是为了防止传入的n比链表总长度还要长
    while(n > 0 && n1){
        n1 = n1.next;
        n--;
    }
    // 说明n确实比链表还要长。
    if(n > 0){
        return head;
    }
    // 经过上面的循环,n1和n2已经相差了n个结点
    while(n1 && n1.next){
        n1 = n1.next;
        n2 = n2.next;
    }
    // 删除
    n2.next = n2.next.next;
    
    return dummy.next;
};

61. Rotate List

给定一个链表,让这个链表向右旋转k位。其中k为非负数。
如:1->2->3->4->5->NULL,k=2

  • 第一次旋转:5->1->2->3->4->NULL
  • 第二次旋转:4->5->1->2->3->NULL

143.Reorder List

给定一个链表L(0)>L(1)>L(2)>.…>L(n-1)>L(n)
将其变为L(O)>L(n)->L(1)->L(n-1)->L(2)->L(n-2)……的形式

  • 链表无法随机访问数据,如何获得中间的元素?
  • 两次遍历可以,但是一次遍历怎么获取?

234.Palindrome Linked List

给一个链表,判断这个链表是否为回文链表。

  • 能否使用0(1)的空间复杂度解决问题?
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消