leetcode——链表篇

老子叫甜甜 提交于 2020-02-18 02:02:57

链表:
链表和
链表右移动k位
翻转链表
两两交换链表节点
链表根据X分区:
删除链表重复元素:
最多出现两次的数组

链表和:
给出两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

public static ListNode addTwoNumber(ListNode l1, ListNode l2) {
		ListNode dumyHead = new ListNode(0);
		ListNode p = l1, q = l2, curr = dumyHead;
		int carry = 0;  // 表示是否需要进位(只有连个值:0跟1)
		while(p != null || q != null) {
			int x = (p != null ) ? p.val : 0; // 需要考虑位数不同的数字相加
			int y = (q != null ) ? q.val : 0;
			int sum = carry + x + y;
			carry = sum / 10;  // 进位携带
			curr.next = new ListNode(sum % 10);
			curr = curr.next;
			if(p != null ) p = p.next;
			if(q != null ) q = q.next;
		}
		// 加到最后一位
		if(carry > 0) {
			curr.next = new ListNode(carry);
		}
		return dumyHead.next;
	}

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

示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head==null)return null;
        int len=0;
        ListNode node=head;
        ListNode preNode=null;
        while(node!=null){
            preNode=node;
            len++;node=node.next;
        }
        preNode.next=head;//形成环链
        k=k%len;
        for(int i=1;i<=len-k;i++){//相当于找到新链表的头结点的上一个节点
            preNode=preNode.next;
        }
        node=preNode.next;
        preNode.next=null;//断开链表
        return node;
        
    } 
}

反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

迭代法,就注意 node.next=null 在循环外进行

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null||head.next==null)return head;
        ListNode node=head;
        ListNode nextNode=head.next;
        node.next=null;
        while(nextNode!=null){
            ListNode Nnext=nextNode.next;
            nextNode.next=node;
            node=nextNode;
            nextNode=Nnext;
        }
        return node;
    }
}

两两交换链表节点:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head==null||head.next==null)return head;
        ListNode node=head.next;
        head.next=node.next;
        node.next=head;
        head.next=swapPairs(head.next);
        return node;  
    }
}

链表根据X分区:
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5

解析:利用三个指针,分别是小数组链表指针,大数组链表指针以及原链表。注意都是原地变化

class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode dummySmall=new ListNode(0);
        ListNode dummyBig=new ListNode(0);
        
        ListNode smallTail=dummySmall;//记录新链表的尾节点
        ListNode bigTail=dummyBig;
        while(head!=null){
            if(head.val>=x){
                if(bigTail==null)bigTail=head;
                else {
                    bigTail.next=head;bigTail=bigTail.next;
                }
            }
            else{
                if(smallTail==null)smallTail=head;
                else {
                    smallTail.next=head;smallTail=smallTail.next;
                }
                
            }
            head=head.next;
        }
        smallTail.next=dummyBig.next;bigTail.next=null;
        return  dummySmall.next;
    }
}

删除链表重复元素:
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:
输入: 1->1->1->2->3
输出: 2->3

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head==null)return null;
        int flag=0;//是否删除pre节点的标志
        ListNode dummy=new ListNode(1);
        ListNode pre=dummy;
        pre.next=head;
        ListNode node1=head;
        ListNode node2=head.next;
        while(node2!=null){
            if(node1.val==node2.val){
                node1.next=node2.next;
                node2=node1.next;
                flag=1;
            }
            else{
            if(flag==1){
                pre.next=node2;
                node1=node2;
                node2=node2.next;
                flag=0;
            }
            else{
                pre=node1;
                node1=node2;
                node2=node1.next;
            }
            }
        }
        if(flag==1)pre.next=node1.next;
        return dummy.next;
    }
}

最多出现两次的数组

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。
你不需要考虑数组中超出新长度后面的元素。

解析:一次遍历,快慢指针,慢指针为新数组的末尾

class Solution {
    public int removeDuplicates(int[] nums) {
        int isDouble=0;//重复标志
        if(nums.length==0||nums.length==1||nums.length==2)return nums.length;
        int z=1;
        for(int i=0,j=1;j<nums.length;i++,j++){
            if(nums[i]==nums[j]){
                if(isDouble==1)continue;
                else{nums[z++]=nums[j];
                isDouble=1;}
            }
            else {
                isDouble=0;
                nums[z++]=nums[j];}
            }
        return z;
        }
    }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!