1、反转单链表
题目介绍: 具体效果图如下: 思路分析:
1、首先设置两个指针,cur指向链表的头结点,prev指向空(默认为null)。 2、为避免cur.next为空,所以引用curNext来暂时保存一下cur的后继节点。 3、让cur的后继节点指向prev。 4、prev指针向后移,即prev指向cur。 5、cur指针也向后移,指向它的下一个节点,即指向curNext节点。 6、循环执行2-5步,直到cur遍历完整个单链表为空为止。
代码如下:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode prev=null;
if(head==null){
return null;
}
while(cur!=null){
ListNode curNext=cur.next;
cur.next=prev;
prev=cur;
cur=curNext;
}
return prev;
}
}
2、给定一个带有头结点 head 的非空单链表,返回链表的中间结点
题目介绍: 思路分析: 该题我们可以使用双指针(快慢指针)的方法 ,快指针速度是慢指针的2倍,那么它的路程也是慢指针的2倍,所以快指针到结尾了,慢指针也就在中间位置了。 1、首先设置两个指针,一个快指针,一个慢指针。 2、快指针每次走两步,慢指针每次走一步。 3、当快指针走到最后一个节点时,慢指针正好走到链表的中间节点。
代码如下:
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast=head;
ListNode slow=head;
if(head==null){
return null;
}
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
}
3、输入一个链表,输出该链表中倒数第k个结点
题目介绍: 思路分析:
1、首先让快指针fast和慢指针slow开始时都指向头结点; 2、让快指针fast走k-1步; 3、让快指针和慢指针同时开始一步一步走,直到快指针走到最后一个节点为止,此时慢指针正好指向倒数第k个节点。
代码如下:
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode fast=head;
ListNode slow=head;
if(k<=0||head==null){
return null;
}
while(k-1!=0){
fast=fast.next;
k--;
}
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
4、将两个有序链表合并为一个新的有序链表并返回
题目介绍: 思路分析:
1、首先设置个傀儡节点; 2、然后比较两个链表的每个节点,依次存入傀儡节点后的链表中; 3、如果有一个链表已经遍历完,则将另一个链表中的其它节点连接到合并链表的尾部; 4、最后返回傀儡节点的下一个节点,这才是合并后的链表的头结点。 代码如下:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newHead=new ListNode(0);
ListNode tmp=newHead;
while(l1!=null&&l2!=null){
if(l1.val<l2.val){
tmp.next=l1;
l1=l1.next;
tmp=tmp.next;
}
else{
tmp.next=l2;
l2=l2.next;
tmp=tmp.next;
}
}
if(l1==null){
tmp.next=l2;
}
else{
tmp.next=l1;
}
return newHead.next;
}
}
5、分割链表
题目介绍:
思路分析: 1、首先创建4个引用,as和ae表示第一个段(用来存放比特定值小的数),bs和be表示第二个段(用来存放比特定值大的数); 2、然后依次遍历原链表,不过需要注意的是,遍历结束后,我们要将第二段尾指针的next置空。因为当前节点引用的是原链表的节点,而其指针可能指向一个小于特定值的节点,所以我们需要切断这个引用。 3、最后让前一段尾结点的指针指向后一段的头结点即可。 代码如下:
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode as = null;
ListNode ae = null;
ListNode bs = null;
ListNode be = null;
ListNode cur = head;
while (cur != null) {
if (cur.val < x) {
if (as == null) {
as = cur;
ae = cur;
} else {
ae.next = cur;
ae = ae.next;
}
} else {
if (bs == null) {
bs = cur;
be = cur;
} else {
be.next = cur;
be = be.next;
}
}
cur = cur.next;
}
if (as == null) {
return bs;
}
ae.next = bs;
if (bs != null)
be.next = null;
return as;
}
}
6、删除该链表中重复的结点,重复的结点不保留
题目介绍: 思路分析: 1、引用变量cur代替头结点对原链表进行遍历; 2、创建个傀儡节点当作新链表,并引用变量tmp代替傀儡节点; 3、在原链表中,让当前节点的值与下一个节点的值进行比较,如果不相等则引入新链表,如果相等,则使cur指向不与这个值相等的那个节点; 4、最后返回新头结点的下一个节点(真正的头结点)。 代码如下:
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode cur = head;
ListNode newHead = new ListNode(0);
ListNode tmp = newHead;
while (cur != null) {
if (cur.next != null && cur.val == cur.next.val) {
while (cur.next != null && cur.val == cur.next.val) {
cur = cur.next;
}
cur = cur.next;
} else {
tmp.next = cur;
tmp = tmp.next;
cur = cur.next;
}
}
tmp.next = null;
return newHead.next;
}
}
7、 链表的回文结构
题目介绍: 思路分析: 1、利用快慢指针找到中间节点; 2、将中间节点后面的节点进行反转; 3、判断头结点的值和尾结点的值是否相同,若不相同则返回false,若相同,则头结点从前往后走,尾结点从后往前走,继续比较,直到两个节点相遇,返回true; 4、我们还要考虑一下偶数链表的情况。 代码如下:
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode fast=head;
ListNode slow=head;
if(head==null){
return true;
}
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
ListNode cur=slow.next;
while(cur!=null){
ListNode curNext=cur.next;
cur.next=slow;
slow=cur;
cur=curNext;
}
while(head!=slow){
if(head.val!=slow.val){
return false;
}
if(head.next==slow){
return true;
}
head=head.next;
slow=slow.next;
}
return true;
}
}
8、输入两个链表,找出它们的第一个公共结点。
题目介绍: 思路分析: 1、引用变量pl和ps,让pl永远指向最长的那个链表,ps永远指向那个最短的链表; 2、计算两个链表的长度并求出两个链表的差值,让那个最长的那个链表先走差值步; 3、遍历两个链表,直到两个链表节点相等,并返回那个节点。 代码如下:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null||headB==null){
return null;
}
ListNode pl=headA;
ListNode ps=headB;
int lenA=0,lenB=0;
while(pl!=null){
lenA++;
pl=pl.next;
}
pl=headA;
while(ps!=null){
lenB++;
ps=ps.next;
}
ps=headB;
int len=0;
len=lenA-lenB;
if(len<0){
pl=headB;
ps=headA;
len=lenB-lenA;
}
while(len!=0){
pl=pl.next;
len--;
}
while(pl!=ps){
pl=pl.next;
ps=ps.next;
}
return pl;
}
}
9、给定一个链表,判断链表中是否有环。
题目介绍: 思路分析: 判断链表是否有环实际上就是一个追击问题,因此我们可以采用双指针的方法,设置一个快指针一个慢指针,快指针每次走两步,慢指针每次走一步。如果链表有环的话,那么快指针和慢指针终究会在环里面相遇。 1、设置一个快指针fast,一个慢指针slow,两个指针刚开始都指向头结点; 2、快指针每次走两步,慢指针每次走一步; 3、如果快指针和慢指针相等了,说明该链表有环返回true,否则该链表无环,返回false。 代码如下:
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null)return false;
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
return true;
}
}
return false;
}
}
10、给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
题目介绍: 思路分析: 由于任意时刻,fast 指针走过的距离都为slow 指针的 2 倍。所以我们可以得到X=(N-1)*C+Y这样的关系式,从中可以发现:从相遇点到入环点的距离加上 N-1圈的环长,正好等于从链表起始点到入环点的距离。 因此,当slow 与 fast 相遇的时候,我们可以使用slow或者fast(本文是让fast指向)指向链表头部;然后,它和 slow 每次向后走一步。最终,它们相遇的节点即是它们的入环点。 1、首先利用快慢指针找到相遇点; 2、找到相遇点之后,让fast指向链表的头节点,然后让头节点和slow同时移动,直到它们相遇; 3、最终,它们相遇的节点即是它们的入环点,返回即可。 代码如下:
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null)return null;
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
fast=head;
while(fast!=slow){
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
return null;
}
}
|