leetcode 链表(java)

@[TOP](leetcode 链表)

leetcode160 链表相交(easy)

题目:
编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表:
在这里插入图片描述
在节点 c1 开始相交。
坑:找相同内存地址的交点(同时相遇)而不是相同数字的节点

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        /**
        定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
        两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
        **/
        if(headA == null || headB == null) return null;
        ListNode pA = headA, pB = headB;
        // 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null==null
        while(pA != pB) {
            pA = (pA == null) ? headB : pA.next;
            pB = (pB == null) ? headA : pB.next;
        }
        return pA;
    }
}

leetcode206 反转链表(easy)

题目:反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

方法一:迭代

第一次循环:
在这里插入图片描述
第二次循环:
在这里插入图片描述

class Solution {
    public ListNode reverseList(ListNode head) {

        ListNode pre = null;  //指向当前节点的前一个节点
        ListNode cur = head;  //当前节点
        ListNode temp = null; //指向当前节点的下一个节点 

        while(cur != null){
            temp = cur.next;  //保存当前节点的下一个节点
            cur.next = pre;   //将当前节点指向pre
            pre = cur;        //将pre和cur都后移一位
            cur = temp;
        }
        return pre;  //最后的一个节点就是pre
    }
}

方法二:头插法

class Solution{
	public ListNode reverseList(ListNode head){
		ListNode newHead = new ListNode(-1);
		ListNode next = null;
		while(head!=null){
			next = head.next;  //保存后面的节点
			head.next = newHead.next;
			newHead.next = head;//插入到新头节点后面
			head = next;//节点后移一位
		}
		return newHead.next;
	}
}	

方法三:递归

// 类似第一种迭代的方法
class Solution {
    ListNode pre = null, tmp = null;
    public ListNode reverseList(ListNode head) {
        if (head == null)
            return pre;
        tmp = head.next;
        head.next = pre;  
        pre = head;  //pre和head后移一位
        head = tmp;
        return reverseList(head);
    }
}

leetcode21 合并两个有序列表

方法一:递归

class Solution {
    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;
        }
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}

方法二:迭代(尾插法)

class Solution {   
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode newHead = new ListNode(-1);
        ListNode tail = newHead;  //由于头节点不能动,所以加一个指示指针
        if(l1 == null){
        	return l2;
        }
        if(l2 == null){
        	return l1;
        }
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                tail.next = l1;
                l1 = l1.next;
            } else {
                tail.next = l2;
                l2 = l2.next;
            }
            tail = tail.next;
            tail.next = l1 == null? l2: l1; //加入最后一个节点
        }
        return newHead.next;
    }
}

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

Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.

方法一:迭代

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode temp = head;
        while( temp.next!= null){
            if(temp.next.val == temp.val){//需值相同,若不加val还有内存地址是不同的
                temp.next = temp.next.next; 
            }else{
                temp = temp.next;
            }
        }
        return head;
    }
}

方法二:递归

public ListNode deleteDuplicates(ListNode head) {
    if (head == null || head.next == null) 
    	return head;
    head.next = deleteDuplicates(head.next);
    return head.val == head.next.val ? head.next : head;
}

leetcode19 删除链表的倒数第N个节点

Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
双指针:快慢指针

  1. fast指针先移动n步
  2. slow和fast同时移动,二者间隔n,当fast移到最后一个节点时,slow即倒数第n个节点
public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode fast = head;
    while (n-- > 0) {   //相当于for循环,循环n次for(;n>0;n--)
        fast = fast.next;
    }
    if (fast == null) return head.next;   //删除头节点
    ListNode slow = head;
    while (fast.next != null) { //不包括删除第二个节点(head.next)
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next;  //删除slow后面的节点
    return head;
} 

leetcode24 两两交换链表中的节点(Medium)

Given 1->2->3->4, you should return the list as 2->1->4->3.
题目要求:不能修改结点的 val 值,O(1) 空间复杂度。

方法一:递归

  1. 找终止条件:当递归到链表为空或者链表只剩一个元素的时候,没得交换了,终止。
  2. 找返回值:返回给上一层递归的值应该是已经交换完成后的子链表。
  3. 单次的过程:因为递归是重复做一样的事情,所以只用考虑某一步是怎么完成的。假设待交换的俩节点分别为head和next,就相当于是一个含三个节点的链表交换前两个节点。
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode next = head.next; //保存头节点的下一个节点,使两两相连
        head.next = swapPairs(next.next); //递归内层的头节点放到外层的头节点后面
        next.next = head;  //把next放到head前面
        return next;  //返回每个子链的头节点
    }
}

方法二:迭代

//此处使用3个指针 pre,l1,l2
public ListNode swapPairs(ListNode head) {
    ListNode newHead = new ListNode(-1);
    newHead.next = head;
    ListNode pre = newHead;
    while (pre.next != null && pre.next.next != null) {
        ListNode l1 = pre.next;
        ListNode l2 = pre.next.next;
        
        l1.next = l2.next;
        l2.next = l1;
        pre.next = l2;

        pre = l1;
    }
    return newHead.next;
}

leetcode445 链表求和(Medium)

Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
7243+564 = 7807

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 
        Stack<Integer> stack1 = new Stack<>();
        Stack<Integer> stack2 = new Stack<>();
        
        while (l1 != null) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int carry = 0;   //进位标志
        ListNode head = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry > 0) {
        //carry>0很重要,防止例如5+5=10时输出为0
            int sum = carry;
            sum += stack1.isEmpty()? 0: stack1.pop();
            sum += stack2.isEmpty()? 0: stack2.pop();
            ListNode node = new ListNode(sum % 10);
            node.next = head;   //头插法
            head = node;
            carry = sum / 10;
        }
        return head;
    }
}

leetcode234 回文链表(easy)

Example 1: Input: 1->2 Output: false
Example 2: Input: 1->2->2->1 Output: true
以 O(1) 的空间复杂度来求解

切成两半,把后半段反转,然后比较两半是否相等。

class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null){
            return true;
        }

        ListNode fast = head.next;    //快慢指针
        ListNode slow = head;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
     
        ListNode cutHead = cut(head,slow.next);
        return isEqual(head,reverse(cutHead));
    }

    private ListNode cut(ListNode head,ListNode cutHead){
        while(head.next != cutHead){
            head = head.next;
        }
        head.next = null;
        return cutHead;
    }

    private ListNode reverse(ListNode head){   //头插法
        while(head == null || head.next == null){
            return head;
        }
        ListNode newHead = null;
        ListNode nextNode = null;
        while(head!=null){
            nextNode = head.next;
            head.next = newHead;
            newHead = head;
            head = nextNode;
        }
        return newHead;
    }
    private boolean isEqual(ListNode l1,ListNode l2){
        while(l1 != null && l2 != null){
            if(l1.val != l2.val){
                return false;
            }else{
                l1 = l1.next;
                l2 = l2.next;
            }
        }
        return true;
    }
}

leetcode725 分隔链表(Medium)

Input: root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
输入被分成了k个连续的部分,并且每部分的长度相差不超过1.前面部分的长度大于等于后面部分的长度。

Example 1:
Input: root = [1, 2, 3], k = 5 Output: [[1],[2],[3],[],[]]
输入输出各部分都应该是链表,而不是数组。
Example 2: 输入的结点 root 的 val= 1, root.next.val = 2, \root.next.next.val = 3, 且 root.next.next.next = null。
第一个输出 output[0] 是 output[0].val = 1, output[0].next = null。
最后一个元素 output[4] 为 null, 它代表了最后一个部分为空链表。

思路:

  1. 遍历链表获取长度 length
  2. length 除以 k 得到每段链表的平均长度 aveLength 和 余数 remainder,remainder 的值就是有多少个长度为 (aveLength + 1) 的子链表排在前面。
    举个例子帮助理解一下 11 / 3 = 3 余 2: 一共有3段,每段平均3个节点,但是剩下了2个节点,剩下的2个节点不能丢啊,得全部塞到子链表里面去。根据题意长的链表排前面,短的链表排后面,所以只有前面的两个子链表一人分担一个多余的节点,如此一来便形成了 4 4 3 的结构。
  3. 接下来按照每个子链表应该的长度[4, 4, 3]去截断给定的链表。
public ListNode[] splitListToParts(ListNode root, int k) {
        int length = 0;
        ListNode cur = root;

        while(cur != null){   
            length++;
            cur = cur.next;
        }
        int avgSize = length / k;   //平均长度
        int mod = length % k;   //余数
        ListNode[] res = new ListNode[k];
        
        cur = root;
        for(int i = 0 ; cur != null && i < k ; i++){
            res[i] = cur;
            int size = avgSize + (mod-- >0 ? 1:0);
            for(int j = 0 ; j < size-1;j++){
                cur = cur.next;
            }
            ListNode next = cur.next;   //保存每个子链表的头节点
            cur.next = null;    //分隔
            cur = next;
        }
        return res;
    }

leetcode328 链表元素按奇偶聚集(Medium)

Input: 2->1->3->5->6->4->7->NULL
Output: 2->3->6->7->1->5->4->NULL
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

思路:将奇节点放在一个链表里,偶链表放在另一个链表里。然后把偶链表接在奇链表的尾部

public class Solution {
    public ListNode oddEvenList(ListNode head) {
        if (head == null) return null;
        ListNode odd = head, even = head.next, evenHead = even;
        while (even != null && even.next != null) {
            odd.next = even.next;
            odd = odd.next;
            even.next = odd.next;
            even = even.next;
        }
        odd.next = evenHead;
        return head;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值