首页 > 编程语言 >代码随想录算法day3 - 链表1

代码随想录算法day3 - 链表1

时间:2024-08-30 09:39:05浏览次数:4  
标签:head val 随想录 day3 next 链表 tmpNode 节点

题目1 203. 移除链表元素

给你一个链表的头节点 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
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104]
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

思路

  1. 使用不带虚拟头的链表进行操作,这样做就需要分为两部分去进行判断,第一部分是链表头到不是val数值的节点,第二部分是不是val数值的节点到链表尾部。因为整个链表要遍历一遍所以时间复杂度为O(n),n为链表长度。

代码

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode * tmpNode;
        while(head!= nullptr && head->val == val)
        {
            tmpNode = head;
            head = head->next;
            delete tmpNode;
        }
        if(head == nullptr) return head;
        ListNode * preNode = head;
        tmpNode = preNode->next;
        while(tmpNode != nullptr)
        {
            if(tmpNode->val == val)
            {
                preNode->next = tmpNode->next;
                delete tmpNode;
                tmpNode = preNode->next;
            }
            else
            {
                preNode = preNode->next;
                tmpNode = tmpNode->next;
            }
        }
        return head;
    }
};
  1. 使用虚拟头

使用虚拟头节点后,将虚拟头节点的next指针指向头节点并让头节点指针暂时指向虚拟头,之后就只需要按顺序判断节点是否满足条件并操作就行了,在最后要注意让头节点指针指向虚拟头节点的next指针。时间复杂度也是O(n)。

代码

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* tmpNode = new ListNode(0, head);
        head = tmpNode;
        while(tmpNode->next != nullptr)
        {
            if(tmpNode->next->val == val)
            {
                ListNode* cur = tmpNode->next;
                tmpNode->next = cur->next;
                delete cur;
            }
            else
            {
                tmpNode = tmpNode->next;
            }
        }
        tmpNode = head;
        head = head->next;
        delete tmpNode;
        return head;
    }
};

题目2 707. 设计链表

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:valnextval 是当前节点的值,next 是指向下一个节点的指针/引用。

如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

示例:

输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]

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

思路

这道题就是考察链表的基本功,可以用单链表或者双链表的形式去做,我使用的是双链表。要注意的就是函数里面开头判断后要及时返回及index计数问题。

代码

//双链表节点类
struct Node
{
    Node* prev;
    Node* next;
    int val;
    Node(int val = 0, Node* Prev = nullptr, Node* Next = nullptr):val(val), prev(Prev), next(Next)
    {}  
};

class MyLinkedList {
public:
    MyLinkedList() {
        head = new Node;
        head->next = head;
        head->prev = head;
        size = 0;
    }
    
    int get(int index) {
        if(index >= size) return -1;
        Node * tmp = head->next;
        while(index--)
        {
            tmp = tmp->next;
        }
        return tmp->val;
    }
    
    void addAtHead(int val) {
        size++;
        Node* tmpNode = new Node(val, head, head->next);
        tmpNode->prev->next = tmpNode;
        tmpNode->next->prev = tmpNode;
    }
    
    void addAtTail(int val) {
        size++;
        Node* tmpNode = new Node(val, head->prev, head);
        tmpNode->prev->next = tmpNode; 
        tmpNode->next->prev = tmpNode;
    }
    
    void addAtIndex(int index, int val) {
        if(index > size) return;
        if(index == size) 
        {
            addAtTail(val);
            return;
        }

        Node*tmpNode = head->next;
        while(index--)
        {
            tmpNode = tmpNode->next;
        }
        Node* newNode = new Node(val, tmpNode->prev, tmpNode);
        newNode->next->prev = newNode;
        newNode->prev->next = newNode;
        size++;
    }
    
    void deleteAtIndex(int index) {
        //index超过链表大小直接返回
        if(index >= size) return;
        Node* tmpNode = head->next;
        while(index--)
        {
            tmpNode = tmpNode->next;
        }
        tmpNode->prev->next = tmpNode->next;
        tmpNode->next->prev = tmpNode->prev;
        delete tmpNode;
        size--;
    }
private:
    Node* head;
    //size用于记录链表大小
    int size;
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

题目3 206. 反转链表

给你单链表的头节点 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指针指向就行了,要注意的就是头节点要指向空。

代码

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr)
        {
            return head;
        }
        ListNode* tmpNode = head->next;
        head->next = nullptr;
        while(tmpNode != nullptr)
        {
            ListNode* next = tmpNode->next;
            tmpNode->next = head;
            head = tmpNode;
            tmpNode = next;
        }
        return head;
    }
};

递归法

这个就是和迭代法类似,将每次迭代的反转操作分为一次递归,这样分而治之最终得出反转链表,需要注意的就是递归终止的结束条件。

代码

class Solution {
public:
    ListNode* reverse(ListNode* lft, ListNode* rht)
    {
        if(rht == nullptr)
        {
            return lft;
        }
        ListNode* tmp = rht->next;
        rht->next = lft;
        return reverse(rht, tmp);
    }
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr)
        {
            return head;
        }
        return reverse(nullptr, head);
    }
};

标签:head,val,随想录,day3,next,链表,tmpNode,节点
From: https://www.cnblogs.com/code4log/p/18388010

相关文章

  • 数据结构-单链表-详解-1
    数据结构-单链表-详解-11.前言2.结点3.打印3.1关于断言3.2下一结点的找法物理结构逻辑结构1.前言在数据结构-顺序表-详解中,我详细介绍了顺序表的实现,而顺序表也有一些缺点:中间,头部插入时,需整体挪动数据,效率低下。空间不够时扩容,有一定的消耗,也可能有一定空间浪费......
  • 数据结构:双向链表
    目录结构体创建链表插入链表头插法尾插法 遍历打印删除更新查找销毁结构体typedefintDataType;typedefstructnode{structnode*pPre;DataTypedata;structnode*pNext;}LinkNode;创建链表LinkNode*CreateDouList(){LinkNode......
  • 代码随想录算法训练营,29日 | 704. 二分查找,27. 移除元素,977.有序数组的平方,209.长度最
    数组基础文档讲解︰代码随想录(programmercarl.com)1.连续空间、相同类型元素2.元素只能覆盖3.二维数组的地址连续吗(C++连续,Java不连续)704.二分查找题目链接:704.二分查找文档讲解︰代码随想录(programmercarl.com)视频讲解︰二分查找日期:2024-08-29思路:第一反应是想到二分查......
  • 力扣: 环形链表
    文章目录需求MapSet快慢指针结尾需求给你一个链表的头节点head,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从0开始)。......
  • 代码随想录算法day2-数组2
    题目1209.长度最小的子数组给定一个含有n个正整数的数组和一个正整数target。找出该数组中满足其总和大于等于target的长度最小的子数组[numsl,numsl+1,...,numsr-1,numsr],并返回其长度。如果不存在符合条件的子数组,返回0。示例1:输入:target=7,nums=[2,......
  • 代码随想录day44 || 1143 最长公共子序列, 1035 不相交的线, 53 最大子序列和, 392 判
    1143最长公共子序列funclongestCommonSubsequence(text1string,text2string)int{ //思路和判断最长公共数组一样 //dp[i][j]表示以text1[i],text2[j]为结尾的最长公共子序列的长度 //iftext1[i]==text2[j]{dp[i+1][j+1]=dp[i][j]+1}else{dp[i+1][j+1]=......
  • 数据结构与算法(循环链表,双向链表)
    循环链表最后一个元素指向首元素带尾指针的循环链表合并双向链表双向链表:在单链表的每个结点里再增加一个指向其直接前驱的指针域prior,这样链表中就形成了有两个方向不同的链,故称为双向链表双向链表插入操作思路代码删除操作思路代码三种链表比较顺序表......
  • 代码随想录算法训练营第四十三天 | 300.最长递增子序列 , 674. 最长连续递增序列 , 718.
    目录300.最长递增子序列 思路1.dp[i]的定义2.状态转移方程3.dp[i]的初始化4.确定遍历顺序 5.举例推导dp数组方法一:动态规划方法二:贪心心得收获 674.最长连续递增序列思路动态规划1.确定dp数组(dptable)以及下标的含义2.确定递推公式3.dp数组如何初始化4.......
  • 代码随想录算法训练营第二十九天(贪心 三)
    力扣题部分:134.加油站题目链接:.-力扣(LeetCode)题面:在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为......
  • 数据结构——单向链表
    链表1.空间可以不连续(理论上长度是无限的)2.访问元素不方便3.链表需要更大的空间存放数据和节点地址4.链表的插入和删除效率很高O(1)单向链表无头单向链表,节点插入在头的话,每次头结点都会变,所以有了有头链表,头结点的pNext总是指向链表的第一个节点1.创建空链表//创建空......