<代码随想录二刷>链表(三)

简介: <代码随想录二刷>链表

141. 环形链表

题目描述


给你一个链表的头节点 head ,判断链表中是否有环。


如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。


如果链表中存在环 ,则返回 true 。 否则,返回 false 。


示例 1:


423647f4c366290a9ca558c747a05de7.png

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

20d96dcf825602dd6b4a84488a43d127.png

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

5b8e999a9cc8e1c1a4a615c10e22ef1f.png

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

思路分析

如何判断是否有环?:快慢指针

分别定义fast和slow指针,分别指向头结点,fast每次移动两个节点,slow每次移动一个节点,如果fast和slow指针在途中相遇,则说明这个链表有环.

这个过程就如同操场跑步一样,跑的快的人在一段时间后就会追上慢的人.


image.gif


参考代码


#include<bits/stdc++.h>
using namespace std;
struct ListNode {
  int val;
  ListNode* next;
  ListNode() {}
  ListNode(int x):val(x),next(nullptr) {
  }
  ListNode(int x,ListNode* next):val(x),next(next) {
  }
};
bool hasCycle(ListNode *head) {
  ListNode *slow = head,*fast = head;
  while(fast!=NULL){
    fast = fast->next;
    if(fast!=NULL) {
      fast = fast->next;
    }else{//没有环 
      continue;
    }
    slow = slow->next;
    if(slow==fast){//有环 
      return true;
    }
  }
  return false;//没有环 
}

142. 环形链表 II

题目描述


给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。


如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。


不允许修改 链表。


示例 1:


d97726a6428fe0e4b9e91f67ae9c02df.png

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点

解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

34012d154a79ce6a221cdd528f0b3186.png

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点

解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

412b3ae106ab76a2ea25b2605c63c7c9.png

输入:head = [1], pos = -1
输出:返回 null

解释:链表中没有环。

思路分析

本题主要考察:

  • 判断链表是否环
  • 如果有环,如何找到这个环的入口

如何判断是否有环?:快慢指针


分别定义fast和slow指针,分别指向头结点,fast每次移动两个节点,slow每次移动一个节点,如果fast和slow指针在途中相遇,则说明这个链表有环.

这个过程就如同操场跑步一样,跑的快的人在一段时间后就会追上慢的人.

image.gif

如果有环,如何找到这个环的入口? ??


从头结点出发一个指针index1,从相遇节点 也出发一个指针index2,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。


证明过程可以参考卡尔大佬的文章,讲的通俗易懂,嘿嘿嘿


参考代码


#include<bits/stdc++.h>
using namespace std;
struct ListNode {
  int val;
  ListNode* next;
  ListNode() {}
  ListNode(int x):val(x),next(nullptr) {
  }
  ListNode(int x,ListNode* next):val(x),next(next) {
  }
};
ListNode *detectCycle(ListNode *head) {
  ListNode* slow = head,*fast= head,*index1,*index2;
  //首先判断有环没有环
  while(fast!=NULL && fast->next!=NULL) {
    fast = fast->next->next;//fast走两步 
    slow = slow->next;//slow走一步 
    if(slow==fast) {//此时如果相遇必定是入口节点 
      index1 = head;
      index2 = slow;
      //寻找环的入口
      while(index1!=index2) {
        index1 = index1->next;
        index2 = index2->next;
      }
      return index1;
    }
  }
  return NULL;//如果无环,则会退出while循环,返回NULL
}

707. 设计链表

题目描述


设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。


在链表类中实现这些功能:


get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。

addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。

addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。

addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。

deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。


思路分析

盲猜面试出这个的可能性很大,很考查基础.

示例:

MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2);   //链表变为1-> 2-> 3
linkedList.get(1);            //返回2
linkedList.deleteAtIndex(1);  //现在链表是1-> 3
linkedList.get(1);            //返回3

参考代码

#include<bits/stdc++.h>
using namespace std;
//很奇怪,按说是可以的... 
class MyLinkedList {
  public:
    //定义链表
    struct LinkedNode {
      int val;
      LinkedNode* next;
      LinkedNode():val(0),next(NULL) {
      };
      LinkedNode(int x):val(x),next(NULL) {
      };
      LinkedNode(int x,LinkedNode* next):val(x),next(next) {
      };
    };
    MyLinkedList() {
      head = new LinkedNode();
      size = 0;
    }
    //获取链表中 index 个节点的值。如果索引无效,则返回-1。
    int get(int index) {
      if(index<0 || index> size-1 ) {
        return -1;
      }
      LinkedNode* cur = head->next;
      while(index--) { //实际上是获得index+1个节点 ,因为index是从0开始的
        cur = cur->next;
      }
      return cur->val;
    }
    // 在链表头部添加节点。
    void addAtHead(int val) {
//      ListNode *newNode = new ListNode(val,head->next);
//      head->next = newNode;
      head->next = new LinkedNode(val,head->next);
      size++;
    }
    //链表尾部添加节点
    void addAtTail(int val) {
      LinkedNode* cur = head;
      while(cur->next) {
        cur = cur->next;
      }
      cur->next = new LinkedNode(val);
      size++;
    }
    //在链表中的第index个节点之前添加值为val 的节点。
    //如果index等于链表的长度,则该节点将附加到链表的末尾
    //如果 index 大于链表长度,则不会插入节点。
    //如果index小于0,则在头部插入节点。
    void addAtIndex(int index, int val) {
      if(index>size) { //如果 index 大于链表长度,则不会插入节点。
        return;
      }
      if(index<0) { //如果index小于0,则在头部插入节点。
        addAtHead(val);
      }
      if(index==size) { //如果index等于链表的长度,则该节点将附加到链表的末尾
        addAtTail(val);
      }
      LinkedNode* cur = head;
      while(index--) {
        cur= cur->next;
      }
      cur->next = new LinkedNode(val,cur->next);
//      ListNode *newNode = new ListNode(val);
//      newNode->next = cur->next;
//      cur->next = newNode;
      size++;
    }
    //如果索引 index 有效,则删除链表中的第 index 个节点。
    void deleteAtIndex(int index) {
      if(index>=size||index<0) {
        return;
      }
      LinkedNode* cur = head;
      while(index--) {
        cur = cur->next;
      }
      LinkedNode* temp = cur->next;
      cur->next = cur->next->next;
      delete temp;
      size--;
    }
    void printLinkedList(){
      LinkedNode* cur = head;
      while(cur->next){
        cout<<cur->next->val<<" ";
        cur = cur->next;
      }
      cout<<endl;
    }
  private:
    //全局变量
    LinkedNode* head;
    int size ;
};
int main() {
  MyLinkedList* obj = new MyLinkedList();
  int param_1 = obj->get(0);
  cout<<param_1<<endl;
  obj->addAtHead(1);
  obj->printLinkedList();
  obj->addAtTail(2);
  obj->printLinkedList();
  obj->addAtIndex(1,3);
  obj->printLinkedList();
  obj->deleteAtIndex(0);
  obj->printLinkedList();
  return 0;
}


备注:代码本身没啥问题,LeetCode关于这个题可能有点不严谨…


如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发。
创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客

相关文章
【数据结构】数组、双链表代码实现
【数据结构】数组、双链表代码实现
|
2天前
leetcode代码记录(移除链表元素
leetcode代码记录(移除链表元素
10 0
|
2天前
|
存储
链表的实现(文末附完整代码)
链表的实现(文末附完整代码)
15 2
|
2天前
在实现链表的代码中,为什么要使用继承而不是组合?
在实现链表的代码中,为什么要使用继承而不是组合?
18 3
|
2天前
|
设计模式 测试技术
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
24 1
|
2天前
【数据结构】双向链表中删除节点的方法实现(代码+详解)
【数据结构】双向链表中删除节点的方法实现(代码+详解)
88 0
|
5月前
数据结构之带头结点的双向循环链表(含全部代码)
数据结构之带头结点的双向循环链表(含全部代码)
34 0
|
2天前
|
算法
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
|
2天前
|
存储
LeetCode刷题---817. 链表组件(哈希表)
LeetCode刷题---817. 链表组件(哈希表)
|
2天前
【移除链表元素】LeetCode第203题讲解
【移除链表元素】LeetCode第203题讲解