链表系列题

链表系列题

移除元素

题目

​ 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

​ 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

​ 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

思路

​ 和移除重复元素是一个道理

代码

public int removeElement(int[] nums,int val){
	if(nums.length==0){
		return 0;
	}
	int j=0;
	for(int i=0;i<nums.length;i++){
		if(nums[i]!=val){
			nums[j]=nums[i];
			j++;
		}
	}
	return j;
}

方法

​ 无

复杂度

​ 时间复杂度:O(n);空间复杂度:O(1)

合并两个有序链表21

题目

​ 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

思路

​ 使用递归的思想,判断链表1的结点和链表2的结点的大小,如果表1的当前结点更大,就传入表2的下一个结点和整个表1,表2大的时候,同理,当有链表为空时,就返回另外一个链表。

方法

​ 无

代码

 public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
     if(l1==null)	return l2;
     if(l2==null)	return l1;
     if(l1.val<l2.val){
         l1.next = mergeTwoLists(l1.next,l2);
         return l1;
     }else{
         l2.next = mergeTwoLists(l1,l2.next);
     	 return l2;
     }
 }

复杂度

​ 时间:N;空间:N;

两数相加(中等题2)

题目

​ 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

思路

​ 由于输入为逆序,所以两个链表的数字可以直接相加。两个链表当前位置的数分别为n1,n2,进位为carry,则和为n1+n2+carry;其中,答案链表处的位置为(n1+n2+carry)%10,而新进位值为(n1+n2+carry)/10。

​ 如果链表长度不同,可以在短的后面补0。遍历完后,如果carry不为零,则需要新增结点。

方法

​ 无

代码

public ListNode addTwoNumbers(ListNode l1,ListNode l2){
    ListNode head = null,tail=null;
    int carry=0;
    while(l1!=null||l2!=null){
      	int n1 = (l1==null)?0:l1.val;
        int n2 = (l2==null)?0:l2.val;
        int sum = n1+n2+carry;
        if(head==null){
            head = tail = new ListNode(sum%10);
        }else{
            tail = new ListNode(sum%10);
            tail = tail.next;
        }
        carry=sum/10;
        if(l1!=null)	l1 = l1.next;
        if(l2!=null)	l2=l2.next;
    }
    if(carry>0){
        tail.next= new ListNode(carry);
    }
    return head;
}

复杂度

​ 时间复杂度:O(max(m,n));空间复杂度:O(max(m,n))

删除排序链表中的重复元素

题目

​ 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

思路

​ 使用双指针法,一个指针pre指着前一个结点,一个指针cur指着当前结点。如果pre的值与cur的值相同,就将pre的next指向cur的next;不同就移动pre,每次都要移动cur指针。

方法

​ 无

代码

public ListNode deleteDuplicates(ListNode head) {
        if(head==null||head.next==null) return head;
        ListNode prev= head,cur=head.next;
        while(cur!=null){
            if(prev.val==cur.val){
                prev.next=cur.next;
            }else{
                prev=cur;
            }
            cur=cur.next;
        }
        return head;
    }

复杂度

​ 时间:N;空间:1

61.旋转链表

题目

​ 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

思路

​ 就是构建一个环,根据k和长度,选择新的头节点。要保证指着的节点就是新的尾节点

方法

​ 无

代码

public ListNode rotateRight(ListNode head, int k) {
        if(head==null||head.next==null) return head;
        int length = 0;
        ListNode cur = head,pre=null;
        while(cur!=null){
            pre=cur;
            cur=cur.next;
            length++;
        }
        int times = k%length;
        pre.next=head;
        ListNode new_tail = head;
        for(int i=0;i<length-times-1;i++){
            new_tail=new_tail.next;
        }
        ListNode new_head = new_tail.next;
        new_tail.next=null;
        return new_head;
    }

复杂度

​ 时间:O(N);空间:1。

82.删除排序链表中的重复元素 2

题目

​ 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。

思路

​ 使用三个指针,加上哑节点,pre作为前置节点,slow作为慢节点,fast作为快节点,当slow和fast的值相同时,就移动fast,直至不同为止,pre的next就为fast,但pre不移动,slow的next指向fast,slow移动,不同时,就三个一起动。

方法

​ 无

代码

public ListNode deleteDuplicates(ListNode head) {
        if(head==null||head.next==null) return head;
        ListNode dummy = new ListNode(0,head);
        ListNode pre = dummy,slow = head,fast = head.next;
        while(fast!=null){
            if(fast.val!=slow.val){
                pre=pre.next;
                slow=slow.next;
            }else{
                while(fast!=null&&fast.val==slow.val){
                    fast=fast.next;
                }
                pre.next=fast;
                slow=fast;
            }
            if(fast!=null) fast=fast.next;
        }
        return dummy.next;
    }

复杂度

​ 空间:1;时间:N。

86.分隔链表

题目

​ 给你一个链表和一个特定值 x ,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。你应当保留两个分区中每个节点的初始相对位置。

思路

​ 先设置两个头节点,一个为small head,一个为large head,然后设置三个指针,一个为s,一个为l,一个为cur指着head,当cur的值小于x时,s的next就指着cur,s移动,大于时,就是使用l,其余同理。结束后,要将l的next置为空,为了防止l的next不为空又小于x的情况。最后将s的next指向large head的next,合并链表。

代码

 public ListNode partition(ListNode head, int x) {
        ListNode sH = new ListNode(0);
        ListNode lH = new ListNode(0);
        ListNode s = sH,l=lH;
        ListNode cur = head;
        while(cur!=null){
            if(cur.val<x){
                s.next = cur;
                s=s.next;
            }else{
                l.next = cur;
                l=l.next;
            }
            cur=cur.next;
        }
        l.next =null;
        s.next = lH.next;
        return sH.next;
    }

复杂度

​ 空间:1;时间:N;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值