力扣刷题Day3

链表理论基础

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

链接的入口节点称为链表的头结点也就是head。

链表的类型:

单链表:

单链表中的指针域只能指向节点的下一个节点。

链表1

双链表:

双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。

双链表 既可以向前查询也可以向后查询。

链表2

循环链表:

链表首尾相连。

链表4 

链表的储存方式

链表在内存中不是连续分布的。

链表是通过指针域的指针链接在内存中各个节点。

所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

链表3

这个链表起始节点为2, 终止节点为7, 各个节点分布在内存的不同地址空间上,通过指针串联在一起。

链表的构造(java):

public class ListNode {
         int val;
         ListNode next;
         ListNode() {} //无参
         ListNode(int val) { this.val = val; }//一个参数
         //两个参数
         ListNode(int val, ListNode next) { this.val = val; this.next = next;}
    }

删除节点: 

链表-删除节点

只要将C节点的next指针 指向E节点就可以了。

那有同学说了,D节点不是依然存留在内存里么?只不过是没有在这个链表里而已。

是这样的,所以在C++里最好是再手动释放这个D节点,释放这块内存。

其他语言例如Java、Python,就有自己的内存回收机制,就不用自己手动释放了。

添加节点:

链表-添加节点

复杂度为O(1)

 数组和链表的对比:

链表-链表与数据性能对比

数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。

链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。

参考资料:代码随想录

 203. 移除链表元素

题目:力扣

涉及如下链表操作的两种方式:

  • 直接使用原来的链表来进行删除操作。
  • 设置一个虚拟头结点在进行删除操作。

这里采用的是第二种方式:

public ListNode removeElements(ListNode head, int val) {
        ListNode result = new ListNode(0);//虚拟结点
        result.next = head;
        ListNode temp = result;//在head前一位,如果head为val需要删除的时候方便操作;
        //如果不用虚拟节点,那么就需要对头节点进行判断,是否为空?是否为val然后将头节点移动
        //head = head.next

        while(head != null){
            if(head.val == val){
                head = head.next;
                temp.next = head;//如果不采用虚拟节点可以这么写:temp.next.next = head
            }else{
                head = head.next;
                temp = temp.next;
            }
        }

        return result.next;
    }

参考资料:

代码随想录

707.设计链表

题目:力扣

自己写了好几次测试用例都出问题 ,研究了下发现在设置变量的时候直接采用了head节点,但是在进行删除、添加头节点操作的时候很容易出现问题。于是改成用虚拟节点。

刚开始打算完全模拟链表,但是index是否有效很难判断,每次都需要遍历并且循环容易出问题,因此增加了size变量。

ps:需要注意边界问题

class Node{
    int val;
    Node next;

    Node(){};
    Node(int val){this.val = val;}
}

class MyLinkedList {

    Node head;//虚拟节点
    //考虑到删除节点 - 设置虚拟节点比较方便
    int size;

    public MyLinkedList() {
        head = new Node(0);
        size = 0;
    }
    
    public int get(int index) {
        if(index <0 || index >= size){ //index = 0, size = 1
            return -1;
        }

        Node cur = head;
        for(int i=0; i<=index; i++){ //注意从虚拟指针开始遍历
            cur = cur.next;
        }

        return cur.val;

    }
    
    public void addAtHead(int val) {
        addAtIndex(0, val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(size, val);
    }
    
    public void addAtIndex(int index, int val) {
        if(index > size) return;
        if(index < 0) index = 0;

        Node cur = head;
        for(int i=0; i<index; i++){//遍历到所需要找的节点的前一位
            cur = cur.next;
        }

        Node addnode = new Node(val);
        addnode.next = cur.next;
        cur.next = addnode;
        size ++;

    }
    
    public void deleteAtIndex(int index) {
        if(index < 0 || index >= size){
            return;
        }

        Node cur = head;
        for(int i=0; i<index; i++){//遍历到所需要找的节点的前一位
            cur = cur.next;
        }

        cur.next = cur.next.next;
        size --;
    }
}

参考资料:代码随想录

206. 翻转链表

题目:力扣

很容易就想到通过迭代的方式,在head前面增加一个null节点,先储存head的下一个节点,然后将head的next指针指向null节点,然后将head向后移动,依次迭代改变链表的指针方向,最后直接输出原来最后一个节点,作为头节点。

但是在实现的时候需要注意循环的写法:

public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(head != null){ //这里不能使用head.next != null,这样最后一个节点遍历不到
            head = head.next;//储存head下一个节点
            cur.next = pre;//换方向
            pre = cur;//移位
            cur = head;//移位
        }

        return pre;//head为null了,pre在head前一位,也就是最后一个节点
    }

还可以使用递归来实现。

参考资料:代码随想录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于力扣刷题C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷题中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷题中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷题中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷题中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷题中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷题中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷题中,使用 string 可以方便地处理字符串相关的问题。 9. 注意边界条件:在力扣刷题中,边界条件往往是解决问题的关键。需要仔细分析题目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷题中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值