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

203.移除链表元素

在这里插入图片描述

这个题目之前做过一次,也通过了,今天二刷以为可以秒A。结果搞了半天还是报空指针异常,今天好好梳理一下:
1、首先,删除链表中的一个节点,为了不影响head节点,我们要定义一个curNode节点。当curNode的下一个节点的值是val的时候,就将curNode.next赋值为curNode.next.next,java会自动回收这个跳过的节点,如图(b)所示。
2、但是,如果要删除的节点是头结点,如图(a)所示,对于头结点来说,需要加一个虚拟节点作为它的curNode,这样才可以和图(b)一样通过curNode.next赋值为curNode.next.next来跳过这个需要删除的节点。
3、其次,我们每次都要判断curNode.next的val是不是要删除的val,所以curNode.next不能是null,while的循环条件应该是curNode.next != null。如图©当curNode.val=1的时候就必须要停止了。
所以代码为:

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyNode = new ListNode();
        dummyNode.next = head;
        ListNode curNode = dummyNode;
        while(curNode.next != null){
            if(curNode.next.val == val){
                curNode.next = curNode.next.next;//如果下一个节点的val为目标val,就跳过下一个节点,curNode.next指向curNode.next.next。
            }else{
                curNode = curNode.next;//如果不是目标val,cuNode向下移动一位即可
            }
        }
        return dummyNode.next;
    }
}

206.反转链表

这道题最核心的地方在于要搞清楚每一个节点的next的方向是如何由向后变成向前的。下面一步一步说明:
在这里插入图片描述
首先定义一个pre节点和一个cur节点,因为cur最终作为尾节点要指向null,所以pre要先定义为null

在这里插入图片描述
下面我们要将cur的next换为pre,那么就会和后面的链表断开连接,因此要备份cur.next,定义为temp
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/4fcb73990ebb402fbcd8f1ee2d712743.png
cur.next改为前一个的pre节点
在这里插入图片描述
我们的pre和cur都需要向下移动一位,以控制后面的节点换方向。但是必须pre先向下移动,因为如果cur先想下变为temp的话,pre就无法再找到cur的位置了
在这里插入图片描述
pre往下移动一位之后,cur再往下移动一位
在这里插入图片描述
这个时候和上一个循环一样,要先备份temp,继续循环
。。。。。
那么当什么时候停止循环呢? 其实当cur为null的时候就可以停止了,因为这个时候cur为null,不需要再让cur指向pre操作了,这个时候就可以停止了,因此while循环的判断条件为while(cur != null)。
代码非常简洁,如下:

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
}

707.设计链表

这道题目需要定义一个全局变量链表的节点数length,增加节点的时候++,删除的时候–。
另外根据题意addAtIndex方法中,如果 index 比长度更大,该节点将不会插入 到链表中。需要判断一下index和length的大小,注意这里当index = length时,就直接将节点接到链表的尾部,当index>length时,直接return。
还有一个注意点是:我们可以先写addAtIndex方法,再写addAtHead和addAtTail方法,直接调用addAtIndex方法即可。注意这俩方法调用addAtIndex方法之后不需要再lenght++,因为addAtIndex中有length++了。
代码如下:

class MyLinkedList {
    int length = 0;
    ListNode dummyNode;
    public MyLinkedList() {
        dummyNode = new ListNode();
    }
    
    public int get(int index) {
        if(index >= length) return -1;
        ListNode cur = dummyNode;
        for(int i = 0;i < index;i++){
            cur = cur.next;
        }
        return cur.next.val;
    }
    
    public void addAtHead(int val) {
        addAtIndex(0, val);//这里调用了addAtIndex方法,里面就已经length++了,所以就不需要再length++了
    }
    
    public void addAtTail(int val) {
        // ListNode newNode = new ListNode(val,null);
        // ListNode curNode = dummyNode;
        // while(curNode.next != null){
        //     curNode = curNode.next;
        // }
        // curNode.next = newNode;
        // length++;
        addAtIndex(length,val);
    }
    
    public void addAtIndex(int index, int val) {
        if(index > length) return;
        ListNode cur = dummyNode;
        for(int i=0;i < index;i++){
            cur = cur.next;
        }        
        ListNode newNode = new ListNode(val,null);
        if(cur.next == null){
            cur.next = newNode;
        }//在没有节点或者在最后一个节点插入的情况下
        else{
            ListNode temp = cur.next;
            cur.next = newNode;
            newNode.next = temp;
        }
        length++;
    }
    public void deleteAtIndex(int index) {
        if(index >= length) return;
        ListNode cur = dummyNode;
        for(int i = 0;i < index;i++){
            cur = cur.next;
        }
        if(index == length-1) cur.next = null;
        else{
           cur.next = cur.next.next;
        }
        length--;
    }
}
class ListNode{
    int val;
    ListNode next;
    ListNode(){}
    ListNode(int val,ListNode next){
        this.val = val;
        this.next = next;
    }
}

/**
 * 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);
 */
  • 27
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我知道了。以下是对您的问题的回答: a. 动态分配内存的方法有很多,可以使用C语言的malloc函数,也可以使用C++中的new操作符,具体方法如下: C语言的malloc函数: ```c struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode)); ``` C++中的new操作符: ```c++ ListNode* node = new ListNode(); ``` b. 初始化单链表需要对链表节点的成员变量进行赋值,以下是一个示例: ```c++ struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; ListNode* head = NULL; ``` c. 头插法创建单链表的示例代码如下: ```c++ ListNode* head = new ListNode(); head->next = NULL; for (int i = 0; i < n; i++) { int x; cin >> x; ListNode* node = new ListNode(x); node->next = head->next; head->next = node; } ``` 尾插法创建单链表的示例代码如下: ```c++ ListNode* head = new ListNode(); head->next = NULL; ListNode* tail = head; for (int i = 0; i < n; i++) { int x; cin >> x; ListNode* node = new ListNode(x); node->next = NULL; tail->next = node; tail = node; } ``` d. 取链表某一位的值可以通过遍历链表来实现,以下是一个示例: ```c++ ListNode* p = head->next; int pos = 3; for (int i = 1; i < pos && p != NULL; i++) { p = p->next; } if (p == NULL) { cout << "链表长度不足" << endl; } else { cout << p->val << endl; } ``` e. 在链表的某一位进行插入操作可以通过遍历链表找到插入位置,然后插入一个新节点来实现,以下是一个示例: ```c++ ListNode* p = head; int pos = 3; for (int i = 1; i < pos && p != NULL; i++) { p = p->next; } if (p == NULL) { cout << "链表长度不足" << endl; } else { int x = 100; ListNode* node = new ListNode(x); node->next = p->next; p->next = node; } ``` f. 遍历链表可以通过循环遍历链表节点来实现,以下是一个示例: ```c++ ListNode* p = head->next; while (p != NULL) { cout << p->val << " "; p = p->next; } cout << endl; ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值