• 数据结构初阶leetcodeOJ题(二)


    目录

    第一题

     思路:

    第二题

     思路

     第三题

    描述

    示例1

     思路

    总结:这种类似的题,都是用快慢指针,相差一定的距离然后输出慢指针。


    第一题

    给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

    示例 1:

    输入:head = [1,2,6,3,4,5,6], val = 6
    输出:[1,2,3,4,5]
    

    示例 2:

    输入:head = [], val = 1
    输出:[]
    

    示例 3:

    输入:head = [7,7,7,7], val = 7
    输出:[]

     方法一

    思路:

    快慢指针:一个指向目标结点,一个指向目标结点的前驱结点。用一个tmp保存pos->next.

                      free()掉目标结点。

    分两种情况:如果只有一个节点或者要删除的结点是首元节点,那么这时pre为NULL,pos                       指向pos;否则pre->next == pos;

     

    1. struct ListNode* removeElements(struct ListNode* head, int val) {
    2. struct ListNode* pre = NULL;
    3. struct ListNode* pos = head;
    4. while(pos!=NULL)
    5. {
    6. if(pos->val==val){
    7. struct ListNode* tmp = pos->next;
    8. free(pos);
    9. pos = tmp;
    10. if(pre==NULL){
    11. head = pos;
    12. }else{
    13. pre->next = pos;
    14. }
    15. }
    16. else
    17. {
    18. pre = pos;
    19. pos = pos->next;
    20. }
    21. }
    22. return head;
    23. }

    方法二: 

    思想;

    创建新链表,用尾插法,尾插法没有改变原指针的next指向所以不用保存next节点,

    但是在free()时要保存下一节点。

     

    1. struct ListNode* removeElements(struct ListNode* head, int val)
    2. {
    3. struct ListNode* cur = head;
    4. struct ListNode* newhead = NULL;
    5. struct ListNode* tail = NULL;
    6. while(cur!=NULL)
    7. {
    8. if(cur->val!=val)
    9. {
    10. if(newhead==NULL){
    11. newhead = tail = cur;
    12. }else{
    13. tail->next = cur;
    14. tail = cur;
    15. }
    16. cur = cur->next;
    17. }else{
    18. struct ListNode* tmp = cur ->next;
    19. free(cur);
    20. cur = tmp;
    21. }
    22. }
    23. if(tail)
    24. tail->next=NULL;
    25. return newhead;
    26. }

     

     

    第二题

    给你单链表的头结点 head ,请你找出并返回链表的中间结点。

    如果有两个中间结点,则返回第二个中间结点。

    示例 1:

    输入:head = [1,2,3,4,5]
    输出:[3,4,5]
    解释:链表只有一个中间结点,值为 3 。
    

    示例 2:

    输入:head = [1,2,3,4,5,6]
    输出:[4,5,6]
    解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

     思路

    用快慢指针:快指针一次走两个,慢指针一次走一个。这样他们的路程之间差二倍。所以输出慢指针,即输出中间节点。

     

    1. struct ListNode* middleNode(struct ListNode* head) {
    2. struct ListNode* slow = head;
    3. struct ListNode* fast = head;
    4. while(fast!=NULL&&fast->next!=NULL)
    5. {
    6. slow = slow ->next;
    7. fast = fast->next->next;
    8. }
    9. return slow;
    10. }

     第三题

    描述

    输入一个链表,输出该链表中倒数第k个结点。

    示例1

    输入:

    1,{1,2,3,4,5}

    复制返回值:

    {5}

     思路

    用快慢指针:快指针比慢指针先走k步,然后两者在同时走。

     

    1. struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    2. // write code here
    3. struct ListNode* pre =pListHead;
    4. struct ListNode* pos = pListHead;
    5. while(k--){
    6. if(pos!=NULL){
    7. pos = pos->next;
    8. }else{
    9. return NULL;
    10. }
    11. }
    12. while(pos!=NULL){
    13. pre = pre->next;
    14. pos = pos->next;
    15. }
    16. return pre;
    17. }

    总结:这种类似的题,都是用快慢指针,相差一定的距离然后输出慢指针。

    第四题 

     给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

    示例 1:

    输入:head = [1,2,3,4,5]
    输出:[5,4,3,2,1]
    

    示例 2:

    输入:head = [1,2]
    输出:[2,1]
    

    示例 3:

    输入:head = []
    输出:[]
    

    提示:

    • 链表中节点的数目范围是 [0, 5000]
    • -5000 <= Node.val <= 5000

    进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

     方法一

     将节点之间的next翻转。

    用三个指针的原因是,只用两个指针翻转时,会导致链表断裂,但是用第三个指针保存下一个节点这样链表就不会断裂。

     

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. //方法一
    9. struct ListNode* reverseList(struct ListNode* head) {
    10. if(head==NULL)
    11. return NULL;
    12. struct ListNode* left = NULL;
    13. struct ListNode* right= head;
    14. struct ListNode* tmp = head->next;
    15. while(right!=NULL)
    16. {
    17. right->next = left;
    18. left = right;
    19. right = tmp;
    20. if(tmp!=NULL)
    21. tmp = tmp->next;
    22. }
    23. return left;
    24. }

    方法二 

    用头插法,注意头插法需要保存指针。尾插法不用保存指针。

    错误总结

     

    (1)注意头插是新结点指向头结点,然后在将新节点设置为头结点。而不是直接将新节点设置为头节点 

    (2)C语言赋值语句,左值是变量,将新节点设置为头结点。newnode = cur;这是头结点为cur

     

    1. //方法二
    2. struct ListNode* reverseList(struct ListNode* head)
    3. {
    4. if(head==NULL)
    5. return NULL;
    6. struct ListNode* cur = head;
    7. struct ListNode* newhead = NULL;
    8. while(cur!=NULL)
    9. {
    10. struct ListNode* next = cur ->next; //保存下一个
    11. cur->next = newhead;
    12. newhead = cur;
    13. cur = next;
    14. }
    15. return newhead;
    16. }

  • 相关阅读:
    【SpringMVC】RESTful风格CRUD实现
    【C++】map / multimap容器
    Linux Docker部署GitLab、GitLab Runner
    eyb:Redis学习(4)
    C#自定义控件:提示未将对象引用设置到对象实例
    java并发编程: Semaphore如何快速实现一个限流器?
    Open3D 点云区域生长分割算法
    辅助驾驶功能开发-功能对标篇(10)-NOA领航辅助系统-威马
    [iOS界面切换- Present And Push]
    实验过程中的问题记录
  • 原文地址:https://blog.csdn.net/qq_62830324/article/details/134422990