Day03 链表算法题的开始

203.移除链表元素

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //如果是头指针
        while(head!=null&&head.val==val){
            head=head.next;
        }
        if(head==null){
            return head;
        }
        ListNode p=head;
        ListNode q=head.next;
        while(q!=null){
            if(q.val==val){
                p.next=q.next;
                q=p.next;
            }else{
            p=p.next;
            q=q.next;
            }
        }
        return head;
    }
}

我的算法没有采用虚拟头节点,采用虚拟头节点会让代码简单很多,但是我没用使用,是想锻炼一下。

这个没什么好说的,就是删除链表节点,待删除节点的前一个节点指向删除节点的下一个节点。

若是头指针直接head指针后移即可。

707.设计链表

class MyLinkedList {
    class Node{
        int val;
        Node next;
        public Node(){}
        public Node(int val){
            this.val=val;
        }
        public Node(int val,Node next){
            this.val=val;
            this.next=next;
        }
    }
    int length;
    Node head;
    Node tail;
    public MyLinkedList() {
       length=0;
       head=null;
       tail=null;
    }
    //改一下
    public int get(int index) {
        if(index>=length){return -1;}
         Node p=head;
        for(int i=0;i<index;i++){
            p=p.next;
        }
        return p.val;
    }
    
    public void addAtHead(int val) {
        Node newHead=new Node(val);
        if(head==null){
            tail=newHead;
        }else{
            newHead.next=head;
        }
        head=newHead;
        length++;
    }
    
    public void addAtTail(int val) {
        Node newTail=new Node(val);
        if(head==null){
         head=newTail; 
        }else{
        tail.next=newTail;
        }
        tail=newTail;
        length++;
    }
    
    public void addAtIndex(int index, int val) {
        if(index>length){return;}
        Node p=head;
        if(index==0){
            addAtHead(val);
        }else if(index==length){
            addAtTail(val);
        }else{
            for(int i=0;i<index-1;i++){
                p=p.next;
            }
            Node newNode=new Node(val,p.next);
            p.next=newNode;
            length++;
        }
    }
    
    public void deleteAtIndex(int index) {
        if(index>=length){return;}
        if(index==0){
            head=head.next;
        }else{
            Node p=head;
            for(int i=0;i<index-1;i++){
                p=p.next;
            }
            if(p.next==tail){
                tail=p;
                p.next=null;
            }else{
                p.next=p.next.next;
            } 
        }
        length--;
    }
}class MyLinkedList {
    class Node{
        int val;
        Node next;
        public Node(){}
        public Node(int val){
            this.val=val;
        }
        public Node(int val,Node next){
            this.val=val;
            this.next=next;
        }
    }
    int length;
    Node head;
    Node tail;
    public MyLinkedList() {
       length=0;
       head=null;
       tail=null;
    }
    //改一下
    public int get(int index) {
        if(index>=length){return -1;}
         Node p=head;
        for(int i=0;i<index;i++){
            p=p.next;
        }
        return p.val;
    }
    
    public void addAtHead(int val) {
        Node newHead=new Node(val);
        if(head==null){
            tail=newHead;
        }else{
            newHead.next=head;
        }
        head=newHead;
        length++;
    }
    
    public void addAtTail(int val) {
        Node newTail=new Node(val);
        if(head==null){
         head=newTail; 
        }else{
        tail.next=newTail;
        }
        tail=newTail;
        length++;
    }
    
    public void addAtIndex(int index, int val) {
        if(index>length){return;}
        Node p=head;
        if(index==0){
            addAtHead(val);
        }else if(index==length){
            addAtTail(val);
        }else{
            for(int i=0;i<index-1;i++){
                p=p.next;
            }
            Node newNode=new Node(val,p.next);
            p.next=newNode;
            length++;
        }
    }
    
    public void deleteAtIndex(int index) {
        if(index>=length){return;}
        if(index==0){
            head=head.next;
        }else{
            Node p=head;
            for(int i=0;i<index-1;i++){
                p=p.next;
            }
            if(p.next==tail){
                tail=p;
                p.next=null;
            }else{
                p.next=p.next.next;
            } 
        }
        length--;
    }
}

这个设计链表我采用了内部类的方式定义了一个Node

而在链表设计上,我通过给链表赋head tail length 使得代码量减小,当然也让代码需要考虑的事情变多了,比如修改删除节点时tail指针的变化。

其中有一次我把length++写在了判断条件外面,导致尾插时会使length数据多加一,然后删除数据的时候链表就出问题了。通过Debug找了出来,这个题主要还是代码量多,一次性写出来不debug很容易出错。

206.反转链表(这个我忘了mark一下后面复习)

反转链表这个题我写了三种不同思路

常规双指针反转

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode q;
        ListNode p=head;
        ListNode pre=null;
        while(p!=null){
            //记录p.next
            q=p.next;
            //反转
            p.next=pre;
            //更新
            pre=p;
            p=q;
        }
        return pre;
        
}
}

通过q指针去记录要反转的节点p的下一个节点,防止让p.next指向pre时节点丢失。

最后当p指针==null时,pre指针就是反转好的链表。

递归实现正向反转

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null){return head;}
        return func(head,null);
    }
    public ListNode func(ListNode head,ListNode pre){
        ListNode p=head.next;
        head.next=pre;
        ListNode ans;
        if(p!=null){
            ans=func(p,head);
            return ans;
        } 
        return head;
    }
}

正向递归就是将前面的链表作为已反转链表然后传递给下一次递归,将该次递归的节点指向这个已反转链表(记得记录这个节点的next作为参数传递给下一次递归)。当遇到head的下一个节点是null时,反转完成。将该节点指针返回,而前面的递归只需要将方法收到的返回值继续返回即可。

递归实现反向反转

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head!=null){
            ListNode p=reverseList(head.next);
            if(p==null){return head;}
            //1.找到链表尾
            ListNode q=p;
            while(q.next!=null){
                q=q.next;
            }
            //2.将自己(head)插入链表尾
            head.next=null;
            q.next=head;
            //3.返回反转的链表
            return p;
        }
        return head;
}
}

这个方法要求的时间复杂度比上面要高,是我第一次写出来的,有点垃圾哈哈。

其实这个也没啥好说的,先递归到链表末尾再进行操作,先遍历已反转链表(方法的返回值)到末尾然后将此次递归的head节点插在末尾。

今日总结

移除链表元素和设计链表都没啥问题,反而是这个反转链表之前做过没有理解,今天再次做的时候就找不到北了,做出来的时从后往前反转的,时间复杂度高了且更麻烦,需要特殊记忆一下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值