目录
6.已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序
10.删除排序链表中的重复节点(有重复的删除重复,只保留一个)
前言
本博文收集一些从《剑指Offer》、《程序员代码面试指南》以及LeetCode部分刷题中总结出来的与链表相关的题目,收集的都是比较简单的,欢迎补充,如果有写错的欢迎批评。持续更新中。
1.反转单链表
public ListNode reverse(ListNode head){
if(head==null||head.next==null){
return head;
}
ListNode pre=null;
ListNode next=null;
while(head!=null){
next=head.next;
head.next=pre;
pre=head;
head=next;
}
return pre;
}
2.反转部分单链表
举个例子吧,假设要反转的链表范围为2~4,将1-2-3-4-5反转为1-4-3-2-5,那么如何做呢?
找到第二个位置的前面一个节点fPre以及第四个位置的后面一个节点tPos,把反转的部分先反转,然后连接fPre和tPos即可。
如果fPre节点为空的话,说明反转部分是包含头节点的,则返回新的头节点
public ListNode reversePartListNode(ListNode head,int from,int to) {
if(head==null||head.next==null) {
return head;
}
ListNode fPre=null;
ListNode tPos=null;
ListNode cur=head;
int len=0;
while(cur!=null) {
len++;
//分别找到fPre和tPos
fPre=len==from-1?cur:fPre;
tPos=len==to+1?cur:tPos;
}
//判断包不包含头节点,如果不包含让cur指向cur的下一个节点
cur=fPre==null?head:fPre.next;
ListNode node2=cur.next;
cur.next=tPos;
ListNode next=null;
while(node2!=tPos) {
next=node2.next;
node2.next=cur;
cur=node2;
node2=next;
}
if(fPre!=null) {
fPre.next=cur;
return head;
}
return cur;
}
3.查找单链表中的倒数第K个结点(k > 0)
定义两个指针,其中一个指针先走k步,然后两个一起走,当第一个指针到达终点时,第二个指针来到倒数第k个节点的位置
删除倒数第k个节点的题也类似,这里不说了
public ListNode kthListNode(ListNode head,int k){
if(head==null){
return head;
}
ListNode cur1=head;
ListNode cur2=head;
while(k>0){
cur1=cur1.next;
}
while(cur1!=null&&cur2!=null){
cur1=cur1.next;
cur2=cur2.next;
}
return cur2;
}
4.查找单链表的中间结点
定义两个指针,一个快指针,一个慢指针,快一次走两步,慢一次走一步,当快指针的next.next为空时,慢指针的位置就是中点位置。
public ListNode MidListNode(ListNode head){
if(head==null||head.next==null){
return head;
}
ListNode cur1=head;
ListNode cur2=head;
while(cur1.next.next!=null&&cur2.next!=null){
cur1=cur1.next.next;
cur2=cur2.next;
}
return cur2;
}
5.从尾到头打印单链表
利用栈
public void printFromEndToStart(ListNode head){
if(head==null){
return;
}
if(head.next==null){
System.out.print(head.val);
}
Stack<ListNode> stack=new Stack<ListNode>();
while(head!=null){
stack.push(head);
head=head.next;
}
while(!stack.isEmpty()){
System.out.print(stack.pop()+",");
}
}
6.已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序
比较简单也不多说
public ListNode MergeListNode(ListNode head1,ListNode head2){
if(head1==null&&head2!=null){
return head2;
}
if(head2==null&&head1!=null){
return head1;
}
ListNode newHead=new ListNode(-1);
ListNode cur=newHead;
while(head1!=null&&head2!=null){
if(head1.val>head2.val){
cur.next=head2;
cur=cur.next;
head2=head2.next;
}else{
cur.next=head1;
cur=cur.next;
head1=head1.next;
}
}
while(head1!=null){
cur.next=head1;
head1=head1.next;
}
while(head2!=null){
cur.next=head2;
head2=head2.next;
}
return newHead.next;
}
7.判断一个单链表是否有环,如果存在环,求第一个入环节点
//判断是否有环,并寻找入环节点
public ListNode isCircle(ListNode head){
//定义两个指针,一个快指针一次走两步,一个慢指针一次走一步,若有环,则必会相遇
ListNode cur1=head;
listNode cur2=head;
while(cur1!=cur2){
if(cur1==null||cur2==null){
return null;
}
cur1=cur1.next.next;
cur2=cur2.next;
}
//寻找入环节点,两个指针再一起走,相遇时就是入环节点
cur1=head;
while(cur1!=cur2){
cur1=cur1.next;
cur2=cur2.next;
}
return cur1;
}
8.判断两个单链表是否相交(分有环和无环),若相交,求交点
1.针对两个无环的链表的情况
(1)分别求出两个链表的长度len1和len2
(2)让长度长的先走(len1-len2)步,然后一起走,走到第一次相同的点就是交点
2.针对两个有环的链表的情况
(1)由于两个链表都有环,我们可以分别求出两个链表的入环节点loop1和loop2
(2)如果loop1和loop2相等,求出两个链表从头节点到loop节点的的长度,同样长的先走,然后一起走,直到第一次相遇,
(3)如果loop1和loop2不相等,如果从loop1出发在回到loop1之前遇到了loop2,则说明两个链表是相交的,否则两个链表就是不相交的。
9.删除排序链表中的重复节点(有重复的全删除)
例如:1-2-3-3-4-4-5,删除后就是1-2-5
public class DeleteRepListNode {
public ListNode remove(ListNode head) {
if(head==null) {
return head;
}
ListNode cur=head;
ListNode pre=null;
boolean flag=false;
while(cur!=null) {
//表示出现重复节点,找出所有的重复的节点
while(cur.next!=null&&cur.val==cur.next.val) {
flag=true;
cur=cur.next;
}
if(!flag) {
pre=cur;
cur=cur.next;
}
else{ //处理重复的节点
flag=false;
if(pre==null) { //表示从头节点开始就重复
head=cur.next;
cur=head;
}else {
pre.next=cur.next;
cur=pre.next;
}
}
}
return head;
}
}
10.删除排序链表中的重复节点(有重复的删除重复,只保留一个)
例如:1-2-3-3-4-4-5,删除后就是1-2-3-4-5
思路:两个指针分别指向链表的第一个结点及第二个结点,即 pre 指向第一个结点、cur 指向第二个结点;若 pre.value == cur.value,则 pre 的 next 指向 cur 的 next ,cur 指向 cur 的 next ;若不等,则 pre 指向 cur,cur 指向 cur 的 next;直到循环结束
public static void deleteRepeteNode(Node head) {
Node pre = head.next;
Node cur;
while (pre != null) {
cur = pre.next;
if (cur != null && (pre.value == cur.value)) {
pre.next = cur.next;
} else {
pre = cur;
}
}
}
11.旋转链表
https://leetcode-cn.com/problems/rotate-list/description/
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
1.首先分析这个k的取值,求出链表的长度len,向右移动的步数m=k%len
2.向右移动怎么做呢?详细步骤在注释里面
public ListNode rotateRight(ListNode head, int k) {
if(head==null){
return head;
}
//1.求出链表长度len
int len=1;
ListNode cur=head;
while(cur.next!=null){
len++;
cur=cur.next;
}
//2.定义要向右移动的步数m
int m=k%len;
if(m==0){
return head;
}
//3.指针从头节点开始向右移动len-m-1,找到要移动的节点的前一个节点pre
ListNode pre=head;
int step=len-m-1;
while(step>0){
pre=pre.next;
step--;
}
ListNode next=pre.next;
//4.保存要移动的节点区间的最后一个节点cur,将pre的next指向cur的next
pre.next=cur.next;
cur.next=head;
return next;
}
12.将单链表的每K个节点之间逆序
package 链表问题;
import java.util.Stack;
/*
* 将单链表的每K个节点之间逆序
*/
public class ReverseKNodes {
public static ListNode reverseKNode(ListNode head,int k) {
if(k<2) {
return head;
}
Stack<ListNode> stack=new Stack<>();
ListNode newHead=head;
ListNode cur=head;
ListNode pre=null;
ListNode next=null;
while(cur!=null) {
next=cur.next;
stack.push(cur);
if(stack.size()==k) {
//求出k个节点逆序之后的最后一个节点
pre=reverse(stack,pre,next);
newHead=newHead==head?cur:newHead;
}
cur=next;
}
return newHead;
}
private static ListNode reverse(Stack<ListNode> stack, ListNode pre, ListNode next) {
// TODO Auto-generated method stub
ListNode cur=stack.pop();
if(pre!=null) {
pre.next=cur;
}
while(!stack.isEmpty()) {
ListNode temp=stack.pop();
cur.next=temp;
cur=temp;
}
cur.next=next;
return cur;
}
public static void main(String[] args) {
ListNode node1=new ListNode(1);
node1.next=new ListNode(2);
node1.next.next=new ListNode(3);
node1.next.next.next=new ListNode(4);
node1.next.next.next.next=new ListNode(5);
node1.next.next.next.next.next=new ListNode(6);
node1.next.next.next.next.next.next=new ListNode(7);
node1.next.next.next.next.next.next.next=new ListNode(8);
ListNode res=reverseKNode(node1,3);
ListNode cur=res;
while(cur!=null) {
System.out.print(cur.val+" ");
cur=cur.next;
}
}
}