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

203.移除链表元素

题目链接: link
视频
文字

1.思路

方法一:直接使用原来的链表来进行删除操作。

  • 时间复杂度 O(n)
  • 空间复杂度 O(1)

移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。
头结点如何移除呢,其实只要将头结点向后移动一位就可以,这样就从链表中移除了一个头结点。

方法二:设置一个虚拟头结点在进行删除操作。

  • 时间复杂度 O(n)
  • 空间复杂度 O(1)

设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了。

2.代码实现

不使用虚拟结点,原列表操作:
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        while((head!=null)&&(head.val==val)){
            head=head.next;
        }
        ListNode cur=head;
        while((cur!=null)&&(cur.next!=null)){
            if(cur.next.val==val){
                cur.next=cur.next.next;
            }
            else{
                cur=cur.next;
            }
        }
        return head;
    }
}
使用虚拟结点:
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head==null)
            return head;
        ListNode dummy= new ListNode(-1,head);
        ListNode cur=dummy;
        while(cur.next!=null){
            if(cur.next.val==val){
                cur.next=cur.next.next;
            }
            else{
                cur=cur.next;
            }
        }
        return dummy.next;
    }
}

707.设计链表

题目链接: link
视频
文字

1.思路

使用了虚拟结点,无论在头结点,中间结点还是尾结点删除或者增加结点都是同样的操作。

2.代码实现

class ListNode{
    int val;
    ListNode next;
    ListNode(){}
    ListNode(int val){
        this.val=val;
        this.next=null;
    }

}
class MyLinkedList {
    int size;//存放的结点个数
    ListNode head;//虚拟头节点
    public MyLinkedList(){
        //初始化链表
        size=0;
        head=new ListNode(0);
    }

    public int get(int index) {
        //判断index是否合法
        if(index<0 || index > size-1){//这里原来写成了size
            return -1;
        }
        else{
            ListNode cur=head;
            while((index--)!=0){//遍历到index的前一个结点
                cur=cur.next;//指针指向index的前一个结点
            }
            return cur.next.val;
        }
    }
    
    public void addAtHead(int val) {
        ListNode cur=new ListNode(val);
        cur.next=head.next;//注意赋值顺序
        head.next=cur;
        size++;
    }
    
    public void addAtTail(int val) {
        ListNode newNode=new ListNode(val);
        ListNode cur=head;
        while(cur.next!=null){
            cur=cur.next;
        }
        cur.next=newNode;
        size++;
    }
    
    public void addAtIndex(int index, int val) {
        /*判断index是否合法
        index=0 在头部插入新结点
        index=size 在尾部插入结点
        index>size  则不会插入结点
        index <0 在头部插入新结点
        */
        if(index>size){
            return;
        }
        else{
            if(index<0){
            index=0;
        }
            ListNode cur=head;
            while(index--!=0){
                cur=cur.next;//此时指向index前一个结点
            }
            ListNode newNode= new ListNode(val);
            newNode.next=cur.next;
            cur.next=newNode;
            size++;
        }
        
    }
    
    public void deleteAtIndex(int index) {
        if(index<0 || index>= size){
            return;
        }
        ListNode cur=head;
        while(index--!=0){
            cur=cur.next;//指向index的前一个结点
        }
        cur.next=cur.next.next;
        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);
 */

206.反转链表

题目链接: link
视频
文字

1.思路

方法一:双指针法
遍历链表,用两个指针改变每个结点的next,需要注意改变每个结点的next时要提前把后一个结点的地址保存在tmp里,其次要注意遍历的中止条件,还要注意改变结点指针方向时的赋值顺序。
Initialization:

ListNode pre = null; A pointer pre is initialized to null. This will eventually become the new head of the linked list, pointing at the end of the reversed list.
ListNode cur = head; A pointer cur is initialized to the head of the original linked list to traverse through each node in the list.
Traversing and Reversing the Linked List:

while (cur != null) { This loop iterates over each node in the original linked list until cur becomes null, indicating the end of the list.
ListNode temp = cur.next; A temporary pointer temp saves the reference to the next node in the original list since the next reference of cur will be modified, and we don’t want to lose the reference to the rest of the original list.
cur.next = pre; The next pointer of the current node cur is reversed to now point back at the previous node pre, performing the reversal of the linked list incrementally.
pre = cur; Move the pre pointer up by one node, setting it equal to cur. This step shifts the pre pointer to the latest reversed part of the list.
cur = temp; Move the cur pointer up by one node, setting it equal to temp, preparing it for the next iteration. This step progresses the traversal through the original list.
Returning the New Head of the Reversed List:

return pre; At the end of the reversal process, the pre pointer is at what used to be the end of the original linked list, which is now the start of the reversed list, so it is returned as the new head.

方法二:递归
递归法实现这道题的逻辑和双指针法相同

2.代码实现

双指针法;
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur=head;
        ListNode pre=null;
        ListNode tmp;
        while(cur!=null)//修改cur指向的结点的指针方向
        {
            tmp=cur.next;
            cur.next=pre;
            //前后指针都向后移一个结点
            pre=cur;
            cur=tmp;
        }
        return pre;
    }
}
递归:
class Solution {
    private ListNode reverse(ListNode cur, ListNode pre){//翻转cur指向的结点
        if(cur==null)
            return pre;
        else{
            ListNode tmp=cur.next;
            cur.next=pre;
            return reverse(tmp,cur);//前后指针后移一位并反转
        }
    }
    public ListNode reverseList(ListNode head) {
        return reverse(head,null);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值