给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解题思路:用一个哨兵节点res定位,然后用两个指针pre和cur,指向这个哨兵节点,其中cur是要删除的节点,用head进行遍历,当head距离cur有n-1时,cur开始移动,pre始终在cur的前一个,直到head指向null,结束后pre.next=pre.next.next就删除了cur,最后返回res.next。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode res=new ListNode(0);//哨兵节点
res.next=head;
ListNode pre=res;
ListNode cur=res;
int i=1; //距离是n-1,所以从1开始
while(head!=null)
{
if(i>=n)
{
pre=cur;
cur=cur.next;
}
head=head.next;
i++;
}
pre.next=pre.next.next;
return res.next;
}
}
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
解题思路:
方法一: 递归
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null && l2==null) return null;
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;
}
}
}
方法二: 使用哨兵节点res,pre用来遍历新的链表,然后再在两个里进行比较,取其中小的那个,最后返回哨兵节点res.next。官方解里有图。
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null && l2==null) return null;
if(l1==null) return l2;
if(l2==null) return l1;
ListNode pre=new ListNode(0);
ListNode res=pre;
while(l1!=null && l2!=null)
{
if(l1.val<l2.val)
{
pre.next=l1;
l1=l1.next;
}else
{
pre.next=l2;
l2=l2.next;
}
pre=pre.next;
}
if(l1!=null) pre.next=l1;
if(l2!=null) pre.next=l2;
return res.next;
}
}
给定一个链表,判断链表中是否有环。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
解题思路:快慢指针,快指针走两步,慢指针走一步,如果相遇说明就有环。
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next== null) return false;
ListNode slow=head;
ListNode fast=head.next;
while(fast!=slow)
{
if(fast==null || fast.next==null) return false;
fast=fast.next.next;
slow=slow.next;
}
return true;
}
}
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
解题思路: 构建一个新的链表,这个链表的每一个值都是给的两个链表值的和,然后考虑进位。用哨兵节点指向我们的新链表。建议看大佬的图解,很直观。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode list=new ListNode(0);
ListNode res=list;
int tmp=0;
while(l1!=null || l2 != null || tmp!=0 )//这个是判断是不是结束,tmp是判断进位后
//的那个是不是结束,比如[5] [5]按照这样是0,1满足条件,而如果没有tmp就变成了0。
{
if(l1!=null)
{
tmp+=l1.val;
l1=l1.next;
}
if(l2!= null)
{
tmp+=l2.val;
l2=l2.next;
}
list.next=new ListNode(tmp%10);//填入后面的值
tmp/=10;//判断是不是进位了,如果没有那么这个就是0。
list=list.next;//新链表后移
}
return res.next;
}
}