代码随想录算法训练营第三天 |203.移除链表元素,707.设计链表,206.反转链表

简介: 代码随想录算法训练营第三天 |203.移除链表元素,707.设计链表,206.反转链表

203.移除链表元素

  • 讲解链接

https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html

  • 看答案前

移除元素:元素所在地址从链表中移除,并且把断掉的链表链接起来。

遇到的困难:知道思路,写不出来。

  • 看答案后

原来这么简单,可为什么我写不出来?

思路:

1 定义一个虚拟头节点,该节点一开始就指向head,这样做的目的是保持处理逻辑的一致性,否则头节点的处理方法还需要另外写代码,使用的虚拟头节点就不要重写了。

2 定义一个临时节点,用于寻找要删除的元素。初始值赋为虚拟节点。

3 依次移动临时节点,发现目标元素就删除。直到移动到链表尾部。

4 删除操作:将要删除元素的后面部分链表临时存储,删除当前元素,再把存储的链表和删除前一个节点连接起来。

  • 代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummy_head = new ListNode(0);//生成一个虚拟头节点
        dummy_head->next = head; //将头节点和链表连起来
        ListNode* curr = dummy_head; //用于遍历链表的指针
        while(curr->next!=nullptr){
            if(curr->next->val == val){
                ListNode* temp_node = curr->next;
                curr->next = curr->next->next;
                delete temp_node;//释放内存
                temp_node = nullptr;
            }else{
                curr = curr->next;
            }
        }
        //因为存在链表头节点被删的可能,如果被删除,不做如下操作而直接返回head则链表地址会指向一个未分配内存的位置,会报错.所以需要重新赋值头节点.
        head = dummy_head->next;//
        return head;
    }
};
  • 总结

虚拟头节点是个好东西,省了好多事。

707.设计链表

讲解链接:

https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html

看解答前:

我的思路:

1 实现个链表节点,很简单但是我实现的方法实在构造函数里实现的节点,这样做不可以,因为每次创建对象都回重新构造构造一个节点。

2 get实现:根据输入的索引返回对应的值。没问题。

3 addAtHead实现:知道在都节点恰插入数据,但是细节没处理好。

4 addAtTail实现:末尾添加就好,直接找到链表末尾新建一个节点链接起来。

5 addAtIndex实现:要考虑索引的大小,这里没注意细节,还是出问题了。

6 deleteAtIndex实现:删除数据后忘记对数据赋予nullptr了。

看解答后:

不得不说虚拟头节点真是好东西。真的可以节省很多事。但是链表的设计过程中index的大小还是要处理好,不然容易出错。两者配合好才行。

代码:

class MyLinkedList {
public:
    struct LInkedNode{
        int val;
        LInkedNode* next;
        LInkedNode(int val):val(val),next(nullptr){
        }
    };
    MyLinkedList():size_(0),dummy_head_(new LInkedNode(0)){
    }
    int get(int index) {
       if(index > size_ - 1||index < 0){
           return -1;
       }
       LInkedNode* curr = dummy_head_->next;
       while(index -- ){
           curr = curr->next;
       }
       int val = curr->val;
       return val;
    }
    void addAtHead(int val) {
       LInkedNode* curr = new LInkedNode(val);
       curr->next = dummy_head_->next;
       dummy_head_->next = curr;
       ++size_;
    }
    void addAtTail(int val) {
        LInkedNode* curr = dummy_head_;
        while(curr->next!=nullptr){
            curr = curr->next;
        }
        curr->next = new LInkedNode(val);
        ++size_;
    }
    void addAtIndex(int index, int val) {
        if(index >size_ )return;
        if(index < 0 )index = 0;
        LInkedNode* curr = dummy_head_;
        while(index--){
            curr = curr->next;
        }
        LInkedNode* tmp = curr->next;
        curr->next = new LInkedNode(val);
        curr->next->next = tmp;      
        ++size_;
    }
    void deleteAtIndex(int index) {
       if(index >=size_||index < 0)return;
       LInkedNode* curr = dummy_head_;
       while(index --){
           curr = curr->next;
       }
       LInkedNode* tmp = curr->next;
       curr->next = curr->next->next;
       delete tmp;
       tmp = nullptr;
       size_--;
    }
private:
int size_;
LInkedNode* dummy_head_;
};
/**
 * 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);
 */

总结:

脑子比手快,脑子能想到,手总是写不出来。。。

206.反转链表

讲解链接:

https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

看解答前:

写过,用的是双指针方法,但是还是忘了,算是复习。

看解答后:

双指针已经看过,再次复习一遍,递归的写了半天还是写错。但是思路确实也比较简单。

代码:

双指针

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
//双指针法
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = nullptr;
        ListNode* curr = head;
        while(curr!=nullptr){
        ListNode* tmp = curr->next;
        curr->next = pre;
        pre =curr;
        curr  = tmp;
        }
        return pre;
    }
};

递归

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode*curr){
        if(curr==nullptr)return pre;
        ListNode* tmp = curr->next;
        curr->next = pre;
        // pre = curr;
        // curr=tmp;
        return reverse(curr,tmp);
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(nullptr,head);
    }
};

总结:

这些题目都是看了答案后才觉得原来如此简单,同时也注意到之前写过的算法里面用到的思路如果不及时复习,后面再次遇到时又会忘记。时间太赶,无法好好整理文章,先这样,加油。已经8.21了,洗漱出门。

相关文章
|
2月前
【力扣】-- 移除链表元素
【力扣】-- 移除链表元素
39 1
|
2月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
56 3
|
25天前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
26天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
58 1
|
1月前
|
存储 缓存 算法
通过优化算法和代码结构来提升易语言程序的执行效率
通过优化算法和代码结构来提升易语言程序的执行效率
|
1月前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
1月前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
47 3
|
1月前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法