!!~:题目来源链接
题目目录
1、找出两个链表的交点
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p=headA,q=headB;
while (p!=q){
p= p==null ? headB : p.next;
q= q==null ? headA : q.next;
}
return p;
}
}
2、链表反转
递归方法(链表中很多题目都可以用递归的思想!)
class Solution{
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p = head.next;
ListNode newHead = reverseList(p);
p.next = head;
head.next = null;
return newHead;
}
}
原地逆转,逐个将元素使用头插法插入到新链表中!
class Solution{
public ListNode reverse(ListNode node){
if(node==null || node.next==null) return node;
ListNode pre=new ListNode();
while (node!=null){
ListNode next=node.next;
node.next=pre;
pre=node;
node=next;
}
return pre;
}
}
3、归并两个有序链表
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode p=new ListNode(0); //新建并申请空间;
ListNode q=p; //用于边遍历边排序
while(l1!=null && l2!=null){
if(l1.val<l2.val){
q.next=l1;
l1=l1.next;
}else{
q.next=l2;
l2=l2.next;
}
q=q.next;
}
q.next= (l1==null) ? l2 : l1;
return p.next; //p.next其实就是新的链表;
}
}
4、从有序链表中删除重复节点
使用递归的方法!
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head==null || head.next==null) return head;
head.next=deleteDuplicates(head.next);
return head.val==head.next.val ? head.next : head;
}
}
5、删除链表中倒数第n个节点
主要还是涉及到快慢指针,需要注意的是当链表只有两个元素时、n即链表长度时…等一些特殊情况;
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast = head;
while (n> 0) {
fast = fast.next;
n--;
}
if (fast == null) return head.next; //需要注意这里!!!
ListNode slow = head;
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}
}
6、交换链表中的相邻节点
也是一种递归思想,就很…简单Nice。
class Solution {
public ListNode swapPairs(ListNode head) {
if(head==null || head.next==null)
return head;
ListNode p=head.next;
head.next=swapPairs(head.next.next);
p.next=head;
return p;
}
}
7、链表两数求和
因为是从链表的尾部计算的,所以要用到Stack!
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<ListNode> stack1=new Stack<>();
Stack<ListNode> stack2=new Stack<>();
while (l1!=null){
stack1.push(l1);
l1=l1.next;
}
while (l2!=null){
stack2.push(l2);
l2=l2.next;
}
int flag=0;
ListNode newhead=new ListNode(0);
ListNode s=newhead;
while (!stack1.isEmpty() || !stack2.isEmpty()){
ListNode p= !stack1.isEmpty() ? stack1.pop() : null;
ListNode q= !stack2.isEmpty() ? stack2.pop() : null;
int a= p!=null ? p.val : 0; //这个写法很多地方都会用到!
int b= q!=null ? q.val : 0;
int num=(a+b+flag)%10;
flag=(a+b+flag)/10;
ListNode node=new ListNode(num);
node.next=s.next;
s.next=node;
}
if(flag!=0){
ListNode node=new ListNode(flag);
node.next=s.next;
s.next=node;
}
return newhead.next;
}
}
8、回文链表
方法一:把所有元素入栈,然后出栈的过程中遍历链表就OK。
class Solution {
public boolean isPalindrome(ListNode head) {
Stack<ListNode> stack=new Stack<>();
ListNode p=head;
while (p!=null){
stack.push(p);
p=p.next;
}
p=head;
while (p!=null){
if(p.val!=stack.pop().val)
return false;
p=p.next;
}
return true;
}
}
方法二:栈的方法还可以优化一下。
class Solution {
public boolean isPalindrome(ListNode head) {
Stack<ListNode> stack=new Stack<>();
ListNode p=head;
while (p!=null){
stack.push(p);
p=p.next;
}
int size=stack.size()/2;
p=head;
while (size>0){
if(p.val!=stack.pop().val)
return false;
p=p.next;
--size;
}
return true;
}
}
方法三:快慢指针,将后面半部分逆转,并比较。
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode fast=head,slow=head;
while (fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
if(fast!=null)
slow=slow.next;
slow=reverse(slow);
fast=head;
while (slow!=null){
if(slow.val!= fast.val)
return false;
slow=slow.next;
fast=fast.next;
}
return true;
}
//逆转后半部分————这里可以用递归的方法
// public ListNode reverse(ListNode node){
// if(node==null || node.next==null) return node;
// ListNode p=node.next;
// ListNode newhead=reverse(p);
// p.next=node;
// node.next=null;
// return p;
// }
//反转链表的另一种方法
public ListNode reverse(ListNode node){
if(node==null || node.next==null) return node;
ListNode pre=null; //注意这里为null,还是新建一个new ListNode(0)是不一样的。
while (node!=null){
ListNode next=node.next;
node.next=pre;
pre=node;
node=next;
}
return pre;
}
}
9、分隔链表
看似复杂其实蛮简单的,主要是要计算出有几个“特殊组”,这些“特殊组”比其他普通组的多一个。
class Solution {
public ListNode[] splitListToParts(ListNode head, int k) {
int len=0;
ListNode p=head;
while (p!=null){
len++;
p=p.next;
}
int m=len%k; //前m个
int n=len/k; //每个有几个
int curlen=0;
ListNode[] res=new ListNode[k];
for(int i=0;i<k;++i){
ListNode newhead=new ListNode();
newhead.next=head;
p=newhead;
if(m>0)
curlen=n+1;
else curlen=n;
while (curlen>0){
head=head.next;
p=p.next;
--curlen;
}
if(p!=null) p.next=null;
--m;
res[i]=newhead.next;
}
return res;
}
}
10、链表元素按奇偶聚集
关键在于要记住“oddend”奇链最后一个,以及"evenend"偶链的最后一个。
class Solution {
public ListNode oddEvenList(ListNode head) {
if(head==null || head.next==null || head.next.next==null) return head;
ListNode oddend=head,evenend=head.next;
while (evenend!=null && evenend.next!=null){
ListNode p=evenend.next;
evenend.next=p.next;
p.next=oddend.next;
oddend.next=p;
oddend=oddend.next;
evenend=evenend.next;
}
return head;
}
}
总结
1、递归是个好方法,链表中很多问题都可以用递归去解决!
2、注意一些特殊情况,即只有一个或两个元素等!