LeetCode中神奇的链表操作

删除节点

相关题目:LeetCode 237

编写一个删除单向链表中某个节点的函数。该题的难点在于,函数传入的参数即为被删除节点本身。因此,无法取得被删除节点的前一个节点,按照常规思路没法做。

实际上,题目在数据规模上给出了提示:被删除节点不会是链表中的最后一个节点。

假设被删除节点为node,既然不能取得node的前面的节点,题目又保证了node->next不为空。自然地,我们要拿node->next作文章:提前把node->next的值转移到node上,然后将node->next删掉!

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
void deleteNode(struct ListNode* node) {    
    node->val = node->next->val;
    node->next = node->next->next;   
}



快慢指针

相关题目:LeetCode 142

给出一个可能存在环的单向链表,找出该链表中环的起始点。一开始的思路是开数组存每个节点的地址,然后遍历链表,去找数组中第一个被重复访问的地址。时间空间复杂度均为 O ( N ) O(N) O(N)

以下方法将空间复杂度优化至 O ( 1 ) O(1) O(1)

  • 令两个指针(slow和fast)同时遍历链表,其中,指针slow每次移动一个节点,指针fast每次移动2个节点。
  • 假设n次迭代后slow和fast重合,此时fast比slow多走了n步,但由于两者重合,意味着fast比slow多走了若干次环。证明n为环中节点数量的整数倍。
  • 新开一个指针ans,令ans从链表头部开始,与slow一起迭代,每次移动1个节点。
  • 无论迭代多少次,slow总是比ans多走n步。也就是说,若ans刚进入环,则必定与slow重合。此时返回ans即为答案。
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *slow = head, *fast = head;
    while(fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast) {
            struct ListNode *ans = head;
            while(slow != ans) {
                slow = slow->next;
                ans = ans->next;
            }
            return ans;
        }
    }
    return NULL;
}

此题的思路也可以用在LeetCode 876,找出链表最中间的节点。令指针slow每次移动一个节点,指针fast每次移动2个节点。当fast抵达链表末尾时,slow正好在链表中间。


寻找倒数的节点

相关题目:LeetCode 1721

给出一个单向链表及整数k,交换链表中正数第k个和倒数第k个节点的值。

常规思路自然是先遍历一遍链表,确定链表中节点个数n,然后再遍历一遍,找到对应的节点交换。实际上,只需一次遍历即可完成。

由于事先知道k,令指针now从head开始直接迭代k次定位到正数第k个节点。然后另一个指针rig也从head开始,与now一起迭代,直到now指向NULL。由于now从第k个节点到NULL一共循环n-k次,与now一同迭代的rig从head开始也迭代n-k次,正好指向了倒数第k个节点。

struct ListNode* swapNodes(struct ListNode* head, int k){
    struct ListNode *lef, *rig = head, *now = head;    
    if (head == NULL || head->next == NULL)
        return head;
    
    int i = k-1;
    while (i>0) {
        now = now->next;
        i--;
    }    
    lef = now;
  
    while (now->next != NULL){
        now = now->next;
        rig = rig->next;
    }
    i = lef->val;
    lef->val = rig->val;
    rig->val = i;
    return head;
}

对于此类要处理链表中倒数某个节点的题目,以上思路同样适用。例如LeetCode 19,删除链表中倒数第k个节点这种题目。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值