线性时间找链表倒数第k个节点

26 篇文章 0 订阅
24 篇文章 0 订阅

题目描述
09年统考的源题,虽然都能得到 O ( n ) O(n) O(n)的复杂度,不过满分做法是双指针,也就是指针扫一遍,其余做法均10分。输入一个链表,输出该链表中倒数第k个结点。

思路
比较直观的想法是辅助空间或者是借助栈、递归等方式实现,不过正解还是双指针,发现408很喜欢靠双指针的思想,用来优化线性复杂度。做法如下:
指针1顺序扫到正数第k个节点,从这时候开始指针2跟着指针1往后扫,当指针1到达尾部时,指针2自然到达倒数第k个位置。其实就是模拟一个K大小得到滑动窗口。以下传入节点是不带头节点的,和408原题有区别,不过思想一致

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        ListNode* p = pListHead;
        ListNode* q = NULL;
        unsigned int idx = 0;
        while (p) {
            if (q) q = q->next;
            if (++idx == k) q = pListHead;
            p = p->next;
        }
        return q;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
线性表的链式存储定义可以通过结构体和指针实现,如下所示: ```c typedef struct Node { int data; // 数据域 struct Node* next; // 指针域,指向下一个节点 } Node, *LinkedList; // 定义Node为结构体类型,LinkedList为指向Node的指针类型 ``` 接下来我们可以实现单链表的创建、插入、删除和查等常用操作。 ### 头插法创建单链表 头插法是指将新节点插入到链表的头部,即新节点成为链表的第一个节点。以下是头插法创建单链表的代码实现: ```c LinkedList createListByHeadInsert(int* arr, int n) { LinkedList head = (LinkedList)malloc(sizeof(Node)); // 创建头节点 head->next = NULL; // 初始时链表为空 for (int i = 0; i < n; i++) { Node* newNode = (Node*)malloc(sizeof(Node)); // 创建新节点 newNode->data = arr[i]; // 赋值 newNode->next = head->next; // 插入到头节点后面 head->next = newNode; } return head; } ``` ### 尾插法创建单链表 尾插法是指将新节点插入到链表的尾部,即新节点成为链表的最后一个节点。以下是尾插法创建单链表的代码实现: ```c LinkedList createListByTailInsert(int* arr, int n) { LinkedList head = (LinkedList)malloc(sizeof(Node)); // 创建头节点 head->next = NULL; // 初始时链表为空 LinkedList tail = head; // tail指向链表的最后一个节点 for (int i = 0; i < n; i++) { Node* newNode = (Node*)malloc(sizeof(Node)); // 创建新节点 newNode->data = arr[i]; // 赋值 newNode->next = NULL; // 新节点插入到尾部,所以指针域为NULL tail->next = newNode; // 插入到链表尾部 tail = newNode; // 更新tail指针 } return head; } ``` ### 插入节点 插入节点操作是将新节点插入到链表的任意位置。以下是插入节点的代码实现: ```c void insertNode(LinkedList list, int index, int data) { int i = 0; Node* p = list; while (p != NULL && i < index - 1) { // 到要插入的位置 p = p->next; i++; } if (p == NULL || i > index - 1) { // 如果超出链表长度,则直接返回 return; } Node* newNode = (Node*)malloc(sizeof(Node)); // 创建新节点 newNode->data = data; // 赋值 newNode->next = p->next; // 插入到p节点后面 p->next = newNode; } ``` ### 删除节点 删除节点操作是将链表中的某个节点删除。以下是删除节点的代码实现: ```c void deleteNode(LinkedList list, int index) { int i = 0; Node* p = list; while (p != NULL && i < index - 1) { // 到要删除的位置 p = p->next; i++; } if (p == NULL || p->next == NULL || i > index - 1) { // 如果超出链表长度,则直接返回 return; } Node* q = p->next; // q指向要删除的节点 p->next = q->next; // 将q节点链表中删除 free(q); // 释放q节点的内存 } ``` ### 查节点节点操作是根据节点的值或者下标查链表中的某个节点。以下是查节点的代码实现: ```c Node* findNodeByValue(LinkedList list, int data) { Node* p = list->next; // p指向第一个节点 while (p != NULL && p->data != data) { // 查值为data的节点 p = p->next; } return p; } Node* findNodeByIndex(LinkedList list, int index) { int i = 0; Node* p = list->next; // p指向第一个节点 while (p != NULL && i < index) { // 查下标为index的节点 p = p->next; i++; } return p; } ``` ### 逆置链表链表逆置是指将链表中的所有节点按照相反的顺序重新排列。以下是逆置链表的代码实现: ```c LinkedList reverseList(LinkedList list) { if (list == NULL || list->next == NULL) { // 如果链表为空或者只有一个节点,则直接返回 return list; } Node* p = list->next; // p指向第一个节点 Node* q = p->next; // q指向p的下一个节点 p->next = NULL; // 将第一个节点的指针域设为NULL while (q != NULL) { // 逐个逆置节点 Node* r = q->next; // r指向q的下一个节点 q->next = p; // 将q的指针域指向p p = q; // 更新p指针 q = r; // 更新q指针 } list->next = p; // 将头节点指向p节点 return list; } ``` 以上就是线性表的链式存储定义以及单链表的创建、插入、删除、查等常用操作的代码实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小胡同的诗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值