剑指 Offer 06: 从尾到头打印链表(easy)

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 1:
输入:head = [1,3,2]
输出:[2,3,1]

限制:
0 <= 链表长度 <= 10000

方法一 用栈解决

通常,这种情况下,我们不希望修改原链表的结构。返回一个反序的链表,这就是经典的“后进先出”
我们可以使用栈实现这种顺序。每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始逐个输出结点的值,给一个新的链表结构,这样链表就实现了反转。

  • 创建一个栈,用于存储链表的节点
  • 创建一个指针,初始时指向链表的头节点
  • 当指针指向的元素非空时,重复下列操作:
    • 将指针指向的节点压入栈内
    • 将指针移到当前节点的下一个节点
  1. /**
  2. * struct ListNode {
  3. * int val;
  4. * struct ListNode *next;
  5. * ListNode(int x) :
  6. * val(x), next(NULL) {
  7. * }
  8. * };
  9. */
  10. class Solution {
  11. public:
  12. vector<int> printListFromTailToHead(ListNode* head) {
  13. stack<int> nodes;
  14. vector<int> result;
  15. ListNode* node = head;
  16. while(node != NULL){
  17. nodes.push(node->val);
  18. node = node->next;
  19. }
  20. while(!nodes.empty()){
  21. result.push_back(nodes.top());
  22. nodes.pop();
  23. }
  24. return result;
  25. }
  26. };

剑指 Offer 22. 链表中倒数第k个节点(easy)

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.

方法一 双指针

算法流程:

  1. 初始化: 前指针 former 、后指针 latter ,双指针都指向头节点 head 。
  2. 构建双指针距离: 前指针 former 先向前走 k 步(结束后,双指针 former 和 latter 间相距 k 步)。
  3. 双指针共同移动: 循环中,双指针 former 和 latter 每轮都向前走一步,直至 former 走过链表 尾节点 时跳出(跳出后, latter 与尾节点距离为 k−1,即 latter 指向倒数第 l 个节点)。
  4. 返回值: 返回 latter 即可。
  1. /*
  2. struct ListNode {
  3. int val;
  4. struct ListNode *next;
  5. ListNode(int x) :
  6. val(x), next(NULL) {
  7. }
  8. };*/
  9. class Solution {
  10. public:
  11. ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
  12. if(pListHead == NULL || k == 0){
  13. return NULL;
  14. }
  15. ListNode *pAhead = pListHead;
  16. ListNode *pBehind = pListHead;
  17. for(unsigned int i = 0; i < k - 1; i++){
  18. if(pAhead->next != NULL){
  19. pAhead = pAhead->next;
  20. }
  21. else{
  22. return NULL;
  23. }
  24. }
  25. while(pAhead->next != NULL){
  26. pAhead = pAhead->next;
  27. pBehind = pBehind->next;
  28. }
  29. return pBehind;
  30. }
  31. };

剑指 Offer 24. 反转链表(easy)

image.png

方法一 替换节点

这个很简单,我们使用三个指针,分别指向当前遍历到的结点、它的前一个结点以及后一个结点。
在遍历的时候,做当前结点的尾结点和前一个结点的替换。

  1. /*
  2. struct ListNode {
  3. int val;
  4. struct ListNode *next;
  5. ListNode(int x) :
  6. val(x), next(NULL) {
  7. }
  8. };*/
  9. class Solution {
  10. public:
  11. ListNode* ReverseList(ListNode* pHead) {
  12. ListNode* pReversedHead = NULL;
  13. ListNode* pNode = pHead;
  14. ListNode* pPrev = NULL;
  15. while(pNode != NULL){
  16. ListNode* pNext = pNode->next;
  17. if(pNext == NULL){
  18. pReversedHead = pNode;
  19. }
  20. pNode->next = pPrev;
  21. pPrev = pNode;
  22. pNode = pNext;
  23. }
  24. return pReversedHead;
  25. }
  26. };

剑指 Offer 25. 合并两个排序的链表(easy)

image.png

方法一 递归连接

先判断输入的链表是否为空的指针。如果第一个链表为空,则直接返回第二个链表;如果第二个链表为空,则直接返回第一个链表。如果两个链表都是空链表,合并的结果是得到一个空链表。

两个链表都是排序好的,我们只需要从头遍历链表,判断当前指针,哪个链表中的值小,即赋给合并链表指针即可。使用递归就可以轻松实现

  1. /*
  2. struct ListNode {
  3. int val;
  4. struct ListNode *next;
  5. ListNode(int x) :
  6. val(x), next(NULL) {
  7. }
  8. };*/
  9. class Solution {
  10. public:
  11. ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
  12. {
  13. //判断指针是否为空
  14. if(pHead1 == NULL){
  15. return pHead2;
  16. }
  17. else if(pHead2 == NULL){
  18. return pHead1;
  19. }
  20. ListNode* pMergedHead = NULL;
  21. if(pHead1->val < pHead2->val){
  22. pMergedHead = pHead1;
  23. pMergedHead->next = Merge(pHead1->next, pHead2);
  24. }
  25. else{
  26. pMergedHead = pHead2;
  27. pMergedHead->next = Merge(pHead1, pHead2->next);
  28. }
  29. return pMergedHead;
  30. }
  31. };

剑指 Offer 35. 复杂链表的复制(medium)

image.png