- (力扣2)给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
- 思路解析:我们在力扣网上可以看出人家给的方法传的是结点,再看看题目说是逆序,所以需要创建一个新的表,那么这个头结点采用虚拟头结点还是真实头结点呢?我们来分析一下,如果采用的是真实头结点,第一个结点创建地时候我们就要进行l1和l2相加,把和放进去,但是如果我们采用虚拟头结点地话,我们第一个结点不让元素,新进来地结点元素(和)往后插入就行,那么问题又来了?我们采用头插法还是尾插法?当然我们在这个问题中采用尾插法,因为人家要求逆序,所以我们还需要记录尾指针,如果l1和l2相加有进位我们还得存储进位的值,关于是否进位我们采用对10取余,将余数放入对于的位置
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head=new ListNode(0); //虚拟头结点
ListNode rear=head; //尾指针
int carry=0; //进位
while(true){
if(l1==null&&l2==null&&carry==0){
break;
}
int num=(l1==null?0:l1.val)+(l2==null?0:l2.val)+carry;
ListNode n=new ListNode(num%10);
rear.next=n;
rear=n;
carry=num/10;
l1=l1==null?null:l1.next;
l2=l2==null?null:l2.next;
}
return head.next;
}
2.(力扣19)给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
- 思路解析:看到这道题的直观想法可能就是,把倒数转换成正数,所以需要先遍历一遍表,遍历完了之后表的长度就知道了,长度-n+1就是正着数的位置,然后删除就可以了,但是能不能有个方法只用遍历一遍?我们可以考虑双指针,正着数和倒着数是不是有个差值,我们可以让一个指针先走,后一个指针后走,从而实现依次遍历就使得删除元素,并遍历出来白哦的元素,例如我们题中给的示例1->2->3->4->5,要删除倒数第二个元素,所以我们定义两个指针,一个先走两次,另一个指针和先走的这个指针一起走,直到先走的指针指向最后一个元素,那么后走的指针的下一个元素就是要删除的元素
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null||head.next==null){
return null;
}
ListNode r=head;
ListNode l=head;
for(int i=0;i<n;i++){
r=r.next;
}
if(r==null){
return head.next;
}
while(r.next!=null){
r=r.next;
l=l.next;
}
l.next=l.next.next;
return head;
}
3.(力扣21)将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
- 解题思路:这道题和之前我们所写的合并两个有序数组的题很相似,如果还没做过合并两个有序数组的小可爱们(感兴趣的话可以点击链接https://blog.csdn.net/qq_44941119/article/details/101000474看一看我之前写的这道题的解题思路,有个大概的了解),思路和它完全一样,这里我就不做过多的分析了,在此大家要注意一个穿针引线的概念。
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head=new ListNode(0);
ListNode p=head;
ListNode p1=l1;
ListNode p2=l2;
while(true){
if(p1==null&&p2==null){
break;
}
if(p1!=null&&p2==null){
p.next=p1;
break;
}else if(p1==null&&p2!=null){
p.next=p2;
break;
}else if(p1.val<=p2.val){
p.next=p1;
p1=p1.next;
}else{
p.next=p2;
p2=p2.next;
}
p=p.next;
}
return head.next;
}
4.(力扣328)给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
示例 1:
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
示例 2:
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL
说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
- 思路解析:看到题目中的节点编号的奇偶性,而不是节点的值的奇偶性,原地算法也就是不能取创建新的链表,空间复杂度应为 O(1)则表明避免我们遍历链表,一个for循环就可以了,同样这个题我们可以采用穿针引线的方法来解决,将奇数串在一起,偶数串在一起,但是因为我们要先奇后偶,也就是说最后一个奇数的下一跳是指向偶数的第一个,所以我们需要记录偶数第一个位置,我们定义两个指针一个指向奇数一个指向偶数,两个指针同时走,但是当数字总个数是奇数的时候,偶先出去,因为偶在奇的前面,偶=null,当数字总数是偶数个的时候,最后的结果是偶的下一跳是null。因为要奇数后面串偶数,所以奇最终不能为null;
public ListNode oddEvenList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode ji=head;
ListNode ou=head.next;
ListNode ouStart=ou;
while(true){
if(ou==null||ou.next==null){
break;
}
ji.next=ji.next.next;
ou.next=ou.next.next;
ji=ji.next;
ou=ou.next;
}
ji.next=ouStart;
return head;
}
5.(力扣141)给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
- 思路解析:题中的pos表示的是位置,我们首先要想到的实在怎样取判断是否有环,比如两个人跑步,一个跑的快一个跑的慢,总有那么一个瞬间跑的快的追上了跑的慢的,这时候不就形成了一个环,这里的两个人就相当于两个指针,所以就引出了快慢指针的概念,fast和slow,两个指针都从头开始,一个快一个慢,两个指针同时走,当fast追上low的时候就是有环,那么什么时候没有环就是fast先为null的时候
public boolean hasCycle(ListNode head) { if(head==null||head.next==null){//判断为空 return false; } ListNode fast=head; //快指针 ListNode slow=head; //慢指针 while(true){ if(fast==null||fast.next==null){ return false; } slow=slow.next; fast=fast.next.next; if(slow==fast){ return true; } } }
6.(力扣142)给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。 -
思路解析:这也是一个环的问题,但是和上一个题不一样的地方是在让你找出环的位置,和上一道题一样采用快慢指针来解决,要找到出环的位置,也就是slow==fast,但是如果fast和slow走的步数一样就不是环,所以要判断出环首先fast==slow,但是前提是两个指针走的步数要不一样,所以我们可以让fast一直往后走,但是slow在fast没走一步后都要从头开始走,这样他们就会有步数不一样但是能够相遇的点,那个相遇的点就是环的位置,所以还需要定义一个变量来统计fast走的步数。
public ListNode detectCycle(ListNode head) {
if(head==null||head.next==null){ //判断为空,然后null
return null;
}
ListNode fast=head; //快指针
ListNode slow=head; //慢指针
int step=0; //记录fast走的步数
while(fast!=null){
fast=fast.next;//fsat一直往后走
step++; //步数++
slow=head; //slow始终从头开始
for(int i=1;i<=step;i++){ //fsat没走一步,slow要从头开始
if(slow==fast&&step!=i){
return slow;
}
slow=slow.next;
}
}
return null;//跳出循环返回null
}