链表双指针经典习题
链表双指针经典习题
- 链表的分解
- 删除排序链表中的重复元素2(重复元素彻底删除)
- 方法一:分解链表
- 方式二:快慢指针
- 递归解法
- 链表的合并
- 丑数2
- 有序矩阵中第k小的元素
- 查找和最小的k对数字
- 两数相加
- 两数相加2
- 回文单链表
- 回文链表
- 迭代和递归翻转单链表
- 反转链表
- 方一:迭代
- 方二: 递归
链表的分解
删除排序链表中的重复元素2(重复元素彻底删除)
链接
方法一:分解链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
//1.分解链表 方式
public ListNode deleteDuplicates(ListNode head) {
ListNode uniqueDummy = new ListNode(101);
ListNode repeatDummy = new ListNode(101);
ListNode res=uniqueDummy;
ListNode cur=head;
//遍历原链表
while(cur!=null){
//cur节点是重复节点
if(cur.next!=null && cur.val==cur.next.val || cur.val==repeatDummy.val){
repeatDummy.next=cur;
repeatDummy=repeatDummy.next;
}else{
//cur不是重复节点
uniqueDummy.next=cur;
uniqueDummy=uniqueDummy.next;
}
cur=cur.next;
}
uniqueDummy.next=null;
return res.next;
}
}
方式二:快慢指针
class Solution {
//快慢指针方法,快指针探路 慢指针更新答案链表
public ListNode deleteDuplicates(ListNode head) {
ListNode dummy = new ListNode(101);
dummy.next=head;
ListNode slow=dummy;
ListNode preFast=dummy;
ListNode fast=head;
while(fast!=null){
if(fast.next!=null && fast.val!=preFast.val && fast.val!=fast.next.val){
//fast节点不重复
slow.next=fast;
slow=slow.next;
}
if(fast.next==null && fast.val!=preFast.val){
slow.next=fast;
slow=slow.next;
}
fast=fast.next;
preFast=preFast.next;
}
slow.next=null;
return dummy.next;
}
}
递归解法
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
//递归解法
//定义:给你一条头结点是head的链表 删除重复元素后返回头结点
public ListNode deleteDuplicates(ListNode head) {
//如果 只有一个节点 或者没有节点 就不用删除
if(head==null || head.next==null){
return head;
}
//如果head节点与后面的节点不同
if(head.val!=head.next.val){
head.next= deleteDuplicates(head.next);
return head;
}
//如果head节点与后面的节点相同
while(head.next!=null && head.val==head.next.val){
head=head.next;
}
return deleteDuplicates(head.next);
}
}
链表的合并
丑数2
链接
class Solution {
public int nthUglyNumber(int n) {
int p2=1,p3=1,p5=1;//指向ugly中的第一个丑数
int val2=1,val3=1,val5=1;//表示三个链表的当前节点
int p=1;//指向ugly的索引,便于更新ugly
int[]ugly=new int[n+1];//ugly[i]:第i个丑数
while(p<=n){
//找出三个链表中当前节点的最小值
int minVal=Math.min(Math.min(val2,val3),val5);
ugly[p++]=minVal;
//更新三个链表的当前节点
if(minVal==val2){
val2=2*ugly[p2++];
}
if(minVal==val3){
val3=3*ugly[p3++];
}
if(minVal==val5){
val5=5*ugly[p5++];
}
}
return ugly[n];
}
}
有序矩阵中第k小的元素
链接
class Solution {
//用优先级队列辅助
//思路:合并多条链表
public int kthSmallest(int[][] matrix, int k) {
//队列里存{matrix[i][j],i,j} 以便找到后面的元素
PriorityQueue<int[]> pq=new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0]-o2[0];
}
});
//maxtrix每一行相当于一条链表
//先把各链表的头结点入队列
for(int i=0;i<matrix.length;i++){
pq.add(new int[]{matrix[i][0],i,0});
}
int res=0;
while(!pq.isEmpty()&&k>0){
int[] pollEle=pq.poll();
res=pollEle[0];
int i=pollEle[1],j=pollEle[2];
//把(i,j+1)的元素入队列
if(j+1<matrix[i].length){
pq.add(new int[]{matrix[i][j+1],i,j+1});
}
k--;
}
return res;
}
}
查找和最小的k对数字
链接
//优先级队列+合并链表
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
//队列里存{sum,i,j},sum是nums[i]+nums[j]
PriorityQueue<int[]> pq=new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0]-o2[0];
}
});
int sz1=nums1.length;
int sz2=nums2.length;
//有sz1条链表,先把各链表的头结点入队列
for(int i=0;i<sz1;i++){
pq.add(new int[]{nums1[i]+nums2[0],i,0});
}
List<List<Integer>> res=new LinkedList<>();
while(!pq.isEmpty()&&k>0){
int[]pollEle=pq.poll();
int i=pollEle[1];
int j=pollEle[2];
LinkedList<Integer> ele=new LinkedList();
ele.add(nums1[i]);
ele.add(nums2[j]);
res.add(ele);
//把[i,j+1]入队列
if(j+1<nums2.length){
pq.add(new int[]{nums1[i]+nums2[j+1],i,j+1});
}
k--;
}
return res;
}
}
两数相加
链接
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode p1=l1;
ListNode p2=l2;
ListNode dummy=new ListNode(-1);
ListNode p=dummy;
int carry=0,add=0;
while(p1!=null&&p2!=null){
add=p1.val+p2.val+carry;
carry=add/10;//进位的
add%=10;
ListNode newNode=new ListNode(add);
p.next=newNode;
p=p.next;
p1=p1.next;
p2=p2.next;
}
while(p1!=null){
add=p1.val+carry;
carry=add/10;
add%=10;
ListNode newNode=new ListNode(add);
p.next=newNode;
p=p.next;
p1=p1.next;
}
while(p2!=null){
add=p2.val+carry;
carry=add/10;
add%=10;
ListNode newNode=new ListNode(add);
p.next=newNode;
p=p.next;
p2=p2.next;
}
if(carry!=0){
//还有进位
ListNode newNode=new ListNode(carry);
p.next=newNode;
p=p.next;
}
p.next=null;
return dummy.next;
}
}
两数相加2
链接
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<Integer> stack=new Stack();
//翻转l1链表
while(l1!=null){
stack.add(l1.val);
l1=l1.next;
}
ListNode head1= new ListNode(stack.pop());
ListNode p1=head1;
while(!stack.isEmpty()){
int cur=stack.pop();
ListNode newNode=new ListNode(cur);
p1.next=newNode;
p1=p1.next;
}
p1.next=null;
//翻转l2链表
while(l2!=null){
stack.add(l2.val);
l2=l2.next;
}
ListNode head2= new ListNode(stack.pop());
ListNode p2=head2;
while(!stack.isEmpty()){
int cur=stack.pop();
ListNode newNode=new ListNode(cur);
p2.next=newNode;
p2=p2.next;
}
p2.next=null;
//开始计算 跟两数相加1一样的
p1=head1;
p2=head2;
int add=0,carry=0;
while(p1!=null && p2!=null){
add=p1.val+p2.val+carry;
carry=add/10;
add%=10;
stack.add(add);
p1=p1.next;
p2=p2.next;
}
while(p1!=null){
add=p1.val+carry;
carry=add/10;
add%=10;
stack.add(add);
p1=p1.next;
}
while(p2!=null){
add=p2.val+carry;
carry=add/10;
add%=10;
stack.add(add);
p2=p2.next;
}
if(carry!=0){
stack.add(carry);
}
ListNode dummy=new ListNode(-1);
ListNode p=dummy;
while(!stack.isEmpty()){
int cur=stack.pop();
ListNode newNode=new ListNode(cur);
p.next=newNode;
p=p.next;
}
p.next=null;
return dummy.next;
}
}
回文单链表
回文链表
链接
方法一:用栈来辅助
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
Stack<Integer> stack=new Stack();
ListNode cur=head;
while(cur!=null){
stack.add(cur.val);
cur=cur.next;
}
cur=head;
while(cur!=null){
int val=cur.val;
int stackVal=stack.pop();
if(val!=stackVal){
return false;
}
cur=cur.next;
}
return true;
}
}
方法二:快慢指针
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
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需要+1
slow=slow.next;
}
//从①head->slow-1 ②fast->slow
ListNode head2= reverse(slow);
while(head2!=null){
if(head.val!=head2.val){
return false;
}
head=head.next;
head2=head2.next;
}
return true;
}
//返回翻转后的链表
ListNode reverse(ListNode head){
if(head==null){
return null;
}
if(head.next==null){//一个节点
return head;
}
ListNode pre=head;
ListNode cur=head.next;
pre.next=null;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
迭代和递归翻转单链表
反转链表
方一:迭代
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
//迭代
public ListNode reverseList(ListNode head) {
if(head==null){
return null;
}
ListNode pre=head,cur=head.next;
pre.next=null;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
方二: 递归
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
//递归翻转
//定义:翻转以head为头结点的链表后并返回头结点
public ListNode reverseList(ListNode head) {
//只有一个节点或者是没有节点 不用翻转直接返回
if(head==null||head.next==null){
return head;
}
//翻转head.next链表 然后head接在他的后面
ListNode realHead=reverseList(head.next);
ListNode tail=head.next;
tail.next=head;
head.next=null;
return realHead;
}
}