Java刷题100天(连载)
Day1
1:链表:876. 链表的中间结点 - 力扣(LeetCode)
原理:使用slow和fast两个引用,slow一次走一步,fast一次走两步。这样当fast走到链表末尾的时候,slow走的距离正好是链表长度的一半
特殊情况:当链表长度为1时,直接返回头节点
链表长度为偶数时:
链表长度为奇数时
注意:应先判断节点是否为空,然后判断下一个节点是否为空
代码:
class Solution {public ListNode middleNode(ListNode head) {if(head.next==null){return head;}ListNode fast = head;ListNode slow = head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;}return slow;} }
2.链表:21. 合并两个有序链表 - 力扣(LeetCode)
思路:先设置一个head1,并设置一个tmp节点来指向头节点,然后设置两个引用l1,l2分别指向两个链表,当l1>l2时让tmp指向l2,同时tmp指向next,l2指向next,反之让tmp指向l1,同时tmp指向next,l1指向next。当其中一个节点指向null时跳出循环,并让tmp指向其中非空链表的head,并直接返回head1
代码:
class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode l1=list1;ListNode l2=list2;ListNode head1=new ListNode(1);ListNode tmp=head1;while(l1!=null&&l2!=null){if(l1.val>l2.val){tmp.next=l2; l2=l2.next;}else{tmp.next=l1; l1=l1.next;}tmp=tmp.next;}tmp.next = (l1!=null) ?l1:l2;return head1.next;} }
3.链表:链表分割_牛客题霸_牛客网
思路:设计两段列表before after,分别设置bs,be as,ae来表示这两个链表的开始和结尾。定义一个指向头结点的引用thead。当thead的值小于x时,让be指向thead(若此时bs==be则让bs和be一起指向thead),同时thead指向下一个节点,be指向下一个节点。若thead的值大于等于x则反之。当thead==null时退出循环,若be==null则be=bs=as,若be!=null则be.next=ae
同时返回bs。
注意:当ae不为空的时候,ae的next要置为null。时刻记住:尾节点的next的必须为空!!!!!
public class Partition {public ListNode partition(ListNode pHead, int x) {ListNode thead=pHead;ListNode bs=null;ListNode be=null;ListNode as=null;ListNode ae=null;while(thead!=null){if(thead.val<x){if(bs==null){bs=be=thead;}else{be.next=thead;be=be.next;}}else{if(as==null){as=ae=thead;}else{ae.next=thead;ae=ae.next;}}thead=thead.next;}if(ae!=null){ae.next=null;}if(bs==null){return as;}else{be.next=as;return bs;}} }
4.链表:链表的回文结构_牛客题霸_牛客网
思路:题目中说空间复杂度为O(1)表示只能在原链表的基础上做修改,那么我们只需要找到中间节点,并将之后的节点反向。这样就可以让头节点和尾节点作比较
注意:调整next 引用时,要将中间的next指向他自己,否则之后的判断回文将进入死循环。
public class PalindromeList {public boolean chkPalindrome(ListNode A) {// write code hereListNode fast=A;ListNode slow=A;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;}//找到中间节点//开始调整next 引用ListNode cur=slow.next;slow.next=slow;while(cur!=null){ListNode curN=cur.next;cur.next=slow;slow=cur;cur=curN;}//开始判断回文while(A!=slow){if(slow.val!=A.val){return false;}A=A.next;slow=slow.next;}return true;} }
5.链表.141. 环形链表 - 力扣(LeetCode)
思路:可以使用快慢引用,快引用一次走两步,慢引用一次走一步,如果快满引用相等,则一定有环。为了防止出现套圈的情况,所以快指针只能比慢指针多一步。
注意:因为只要没有空引用就一定有环,所以可以设计成死循环
代码:
public class Solution {public boolean hasCycle(ListNode head) {ListNode slow=head;ListNode fast=head;while(true){if(fast==null||fast.next==null){return false;}fast=fast.next.next;slow=slow.next;if(fast==slow){return true;}}} }
6.链表142. 环形链表 II - 力扣(LeetCode)
思路:在上一题的基础上,我们已经可以判断是否有环,下面我们来判断一下环的入口
不妨设链表到入口的距离为X,环的长度是R,相遇点到入口的距离是L,那么入口到相遇点的距离就是R-L
前提:快引用的速度是慢引用的两倍
Fast = X + nR + R - L(块引用可能走了不只一圈才追上慢引用)
Slow= X + R - L (慢引用入圈时和快引用的距离不会超过R,每走一次距离就缩小一次,所以慢引用不可能走完一圈)
Fast = 2 * Slow
X = ( n - 1 )R + L
当n=1时,X=L
当n=2,3,4...的情况和n=1推导出的情况一样,因为快引用多走一圈不影响最后的相遇点
所以此时相遇点到入口的距离等于头节点到入口的距离
代码:
public class Solution {public ListNode detectCycle(ListNode head) {ListNode slow=head;ListNode fast=head;while(true){if(fast==null||fast.next==null){return null;}fast=fast.next.next;slow=slow.next;if(fast==slow){break;}}while(head!=slow){head=head.next;slow=slow.next;}return slow;} }
7.链表.2. 两数相加 - 力扣(LeetCode)
思路:首先我们要设计一个链表来存储计算的结果,定义链表的头为head,尾为tail。因为两个链表的长度不确定,所以循环的条件为其中一个链表不为空。定义三个整数,其中两个整数分别来存储两个节点的数据,如果节点为空,那么存储0,最后一个整数carry用来存储求和结果十位上的数字。最后将存储求和结果的节点连接起来。退出循环后,如果carry不等于零,那么再连接上存储carry的节点。
代码:
class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode head=null;ListNode tail=null;int carry=0;while(l1!=null || l2!=null){int a1= l1!=null ? l1.val : 0 ; int a2= l2!=null ? l2.val : 0 ;int add=a1+a2+carry;if(head==null){head=tail=new ListNode(add%10);}else{tail.next=new ListNode(add%10);tail=tail.next;}carry= add/10;if(l1!=null){l1=l1.next;}if(l2!=null){l2=l2.next;}}if(carry!=0){tail.next=new ListNode(carry);tail=tail.next;}tail.next=null;return head;} }注意:虽然这题的尾节点的next本身就为null,但是为了养成好习惯,还是选择手动置空。













