java链表奇数倒序偶数顺序_常考算法面试题系列:链表的操作

链表

链表存储有序的元素集合,但不同于数组,链表中每个元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的节点(也称为指针或链接)组成,下图展示了一个链表的结构。

40d24defe06f3d63ea82c586879b6ba0.png

链表

由于不必须按顺序存储,链表在插入的时候可以达到 O(1) 的复杂度,但是查找一个节点或者访问特定编号的节点则需要 O(n)的时间.

题目列表

leetcode206.反转链表

[1]

leetcode324.回文链表

[2]

leetcode876. 链表的中间结点

[3]

面试题 02.02. 返回倒数第 k 个节点

[4]

面试题52. 两个链表的第一个公共节点

[5]

1. 反转链表

使用迭代:在遍历列表时,将当前节点的 next 指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针来存储下一个节点。不要忘记在最后返回新的头引用。

35bb01bcad444a784e5853555330d364.gif

img

/**

* Definition for singly-linked list.

* function ListNode(val) {

* this.val = val;

* this.next = null;

* }

*/

/**

* @param {ListNode} head

* @return {ListNode}

*/

var reverseList = function(head){

let prevNode = null; // 前指针节点

//每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移

while(head != null) {

let tempNode = head.next; //临时节点,暂存当前节点的下一节点,用于后移

head.next = prevNode; //将当前节点指向它前面的节点

prevNode = head; //前指针后移

head = tempNode; //当前指针后移

}

return prevNode;

};

2. 回文链表

用快慢指针遍历的同时翻转前半部分,然后与后半部分比较即可。

/**

* Definition for singly-linked list.

* function ListNode(val) {

* this.val = val;

* this.next = null;

* }

*/

/**

* @param {ListNode} head

* @return {boolean}

*/

var isPalindrome = function(head){

if(head === null || head.next === null) {

return true;

}

let mid = head;

let pre = null;

let reversed = null;

// 快慢指针找出中间节点

while(head !== null && head.next !== null) {

pre = mid;

mid = mid.next;

head = head.next.next;

// 反转前半段

pre.next = reversed;

reversed = pre;

}

// 如果是奇数个

if(head) {

mid = mid.next;

}

// 将反转完之后的前半段和后半段做对比

while(mid) {

if(reversed.val !== mid.val) {

return false;

}

reversed = reversed.next;

mid = mid.next;

}

return true;

};

3.找出链表的中间节点

快慢指针做法:

使用慢指针 slow 和快指针fast 两个指针同时遍历链表。快指针一次前进两个结点,速度是慢指针的两倍

这样,当快指针到达链表尾部时,慢指针正好到达链表的中部。

c6019d35416e73ce1eed13abe3b4f9e2.gif

img

/**

* Definition for singly-linked list.

* function ListNode(val) {

* this.val = val;

* this.next = null;

* }

*/

/**

* @param {ListNode} head

* @return {ListNode}

*/

var middleNode = function(head){

let fast = head;

let slow = head;

// 循环的条件是 fast != null && fast.next != null,防止出现空指针异常。

while(fast && fast.next) {

slow = slow.next;

fast = fast.next.next;

}

// 链表元素为奇数个时,slow 指向链表的中点

// 链表元素为偶数个时,slow 指向链表两个中点的右边一个

return slow;

};

4. 倒数第K个节点

初始化: 使用双指针,i, j

构建双指针距离: 先将i向后移动k次,此时 i,j的距离为k

双指针共同移动: 同时移动i,j,直到i指向 null,此时j位置的val就是答案

返回值

89595bcdb45930e8d2d5e626959636ce.png

img

/**

* Definition for singly-linked list.

* function ListNode(val) {

* this.val = val;

* this.next = null;

* }

*/

/**

* @param {ListNode} head

* @param {number} k

* @return {number}

*/

var kthToLast = function(head, k){

let p = head;

for(let i = 0; i < k; i++) {

p = p.next;

}

while(p) {

p = p.next;

head = head.next;

}

return head.val;

};

5.两个链表的第一个公共节点

我们使用两个指针 node1,node2 分别指向两个链表 headA,headB 的头结点,然后同时分别逐结点遍历,当 node1 到达链表 headA 的末尾时,重新定位到链表 headB 的头结点;当 node2 到达链表 headB 的末尾时,重新定位到链表 headA 的头结点。

这样,当它们相遇时,所指向的结点就是第一个公共结点。

1d6aa6d37eadc50018bf31e123e144d7.gif

getIntersectionNode

/**

* @param {ListNode} headA

* @param {ListNode} headB

* @return {ListNode}

*/

var getIntersectionNode = function(headA, headB){

let node1 = headA;

let node2 = headB;

while(node1 !== node2) {

node1 = node1 ? node1.next : headB;

node2 = node2 ? node2.next : headA;

}

return node1;

};

参考

题解参考 leetcode官方题解。具体的可以去leetcode官网查看。

参考资料

[1]

leetcode206.反转链表: https://leetcode-cn.com/problems/reverse-linked-list/

[2]

leetcode324.回文链表: https://leetcode-cn.com/problems/palindrome-linked-list/

[3]

leetcode876. 链表的中间结点: https://leetcode-cn.com/problems/middle-of-the-linked-list/

[4]

面试题 02.02. 返回倒数第 k 个节点: https://leetcode-cn.com/problems/kth-node-from-end-of-list-lcci/

[5]

面试题52. 两个链表的第一个公共节点: https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值