前言
敲敲敲
在写链表的算法题之前先手撕一下链表的几个基本功能吧。(一定要多练习!!!)
class Node{
public int data;
public Node next;
public Node(int data){
this.data = data;
}
}
public class SingleLinkedList {
public Node head;
public void addFirst(int data){
Node node =new Node(data);
if(this.head==null){
this.head=node;
return;
}
node.next=this.head;
this.head=node;
}
public void display(){
Node cur=this.head;
while(cur!=null){
System.out.print(cur.data);
cur=cur.next;
}
System.out.println();
}
public void addEnd(int data){
Node node =new Node(data);
if(this.head==null){
this.head=node;
return;
}
Node cur=this.head;
while(cur.next!=null){
cur=cur.next;
}
cur.next=node;
}
public boolean contains(int key){
Node cur=this.head;
while(cur!=null){
if(cur.data==key){
return true;
}
cur=cur.next;
}
return false;
}
public int size(){
Node cur=this.head;
int count=0;
while(cur!=null){
count++;
cur=cur.next;
}
return count;
}
public void addIndex(int index,int data){
Node note=new Node(data);
if(index==0){
addFirst(data);
return;
}
if(index==this.size()){
addEnd(data);
return;
}
Node cur=this.head;
while(index-1!=0){
cur=cur.next;
index--;
}
note.next=cur.next;
cur.next=note;
}
public void deleteKey(int key){
if(this.head==null){
throw new RuntimeException("链表已经空了");
}
if(this.head.data==key){
this.head=this.head.next;
return;
}
Node prev=searchPrev(key);
if(searchPrev(key)==null){
System.out.println("没有要删除的元素");
return;
}
prev.next=prev.next.next;
}
private Node searchPrev(int key){
Node prev=this.head;
while(prev.next!=null) {
if (prev.next.data == key) {
return prev;
} else {
prev = prev.next;
}
}
return null;
}
public void removeAll(int key){
if(this.head==null){
throw new RuntimeException("链表已经空了");
}
Node prev=this.head;
Node cur=prev.next;
while(cur!=null){
if(cur.data!=key){
prev=prev.next;
cur=cur.next;
}else{
prev.next=cur.next;
cur=cur.next;
}
}
if(this.head.data==key){
this.head=this.head.next;
}
}
public void clear(){
this.head=null;
}
}
一、反转链表
题目: 代码:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev=null;
ListNode cur=head;
ListNode newHead=null;
ListNode curNext=null;
while(cur!=null){
curNext=cur.next;
if(curNext==null){
newHead=cur; 新的链表的头结点就是老链表的头结点
}
cur.next=prev; 让后面的节点指向前面的节点完成翻转
prev=cur; 前驱节点向后移动
cur=curNext; cur节点向后移动,curNext相当于一个临时变量储存cur的下一个节点,
}
return newHead;
}
}
二、链表的中间节点(力876)
题目:
class Solution {
public ListNode middleNode(ListNode head) {
ListNode curSlow=head; 快慢指针法,快指针走两下慢指针走一下,
只要快指针不为null(奇数个节点)或者快指针
的下一个节点不为null(偶数个节点)就继续走。
ListNode curFast=head;
while(curFast!=null&&curFast.next!=null){
curSlow=curSlow.next;
curFast=curFast.next.next;
}
return curSlow;
}
}
三、倒数第k个节点(剑22)
题目:
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode fast=head;
ListNode slow=head;
if(k<=0){ k合法性判断
return head;
}
int n=k-1; 让快指针先走k-1步,然后快慢指针一起走,当快指针.next为null
while(n>0){ 则停止。此时slow所指向的位置就是要返回的头结点。
fast=fast.next;
n--; 注意一下循环条件中fast!=null指的是最终fast将指向null,而
} fast.next!=null指的是最终fast会指向最后一个节点,这里应该用
while(fast.next!=null){ 后者
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
四、分割链表
题目:
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode bs=null;
ListNode be=null; 创建了四个节点分别指向前链表的头尾结点。后链表的头尾节点。cur
ListNode as=null; 用来遍历原始链表。
ListNode ae=null;
ListNode cur=head;
while(cur!=null){ 一个一个遍历所有的节点,小于x的插入到前面的链表,大于等于x
if(cur.val<x){ 的插入到后面的链表。
if(bs==null){
bs=cur;
be=cur;
}else{
be.next=cur;
be=be.next;
}
}else{
if(as==null){
as=cur;
ae=cur;
}else{
ae.next=cur;
ae=ae.next;
}
}
cur=cur.next;
}
if(bs==null){ 判断要是前面的链表为空,则返回后面的链表的头结点就行了,注意
if(ae!=null){ 把后面链表的尾节点的next置空,不然链表就死循环了。
ae.next=null;
}
return as;
}else{ 前面的链表要是不为空
be.next=as; 就把前面链表的尾结点和后面链表的头结点链接起来
if(ae!=null){
ae.next=null; 最后把尾结点的next置空
}
return bs;
}
}
}
五、回文链表
题目:
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode slow=head;
ListNode fast=head;
if(head==null){ 当链表为空力扣默认true牛客默认false
return true;
}
if(head.next==null){ 当链表只有一个元素肯定是啦
return true;
}
while(fast!=null&&fast.next!=null){ 我们先根据第二题的方法找到链表的中间节点slow
slow=slow.next;
fast=fast.next.next;
}
ListNode cur=slow.next; 用cur来遍历从slow开始到null的所有节点,让他们
while(cur!=null){ 指向自己前面的节点
ListNode curNext=cur.next; 这里就和反转链表一样了,只不过把前驱结点prev换成
cur.next=slow; 了solw
slow=cur;
cur=curNext;
}
while(head!=slow){
if(head.val!=slow.val){ 这时候slow已经指向最后了,不过他这时候已经被翻转
return false; 往前指向了,只要不相等就不是回文
}
if(head.next==slow){ 判断head.next是不是slow,比如元素个数为偶数1221
return true;
}
head=head.next; 分别向中间靠拢一个元素
slow=slow.next;
}
return true;
}
}
六、环形链表(力141)
题目:
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow=head; 定义一个快慢指针指向头结点
ListNode fast=head;
while(fast!=null&&fast.next!=null){ fast和fast.next都不可以是null,不然就空指针了
fast=fast.next.next; 快指针一次向后移动两个节点
slow=slow.next; 慢指针一次向后移动一个节点
if(fast==slow){ 如果快指针和慢指针再次相遇则这是一个环形链表
return true;
}
}
return false;
}
}
七、两个链表的第一个公共节点(剑52)
题目:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int len1=0;
int len2=0;
ListNode cur1=headA;
while(cur1!=null){
len1++;
cur1=cur1.next;
}
ListNode cur2=headB;
while(cur2!=null){
len2++;
cur2=cur2.next;
}
cur1=headA;
cur2=headB;
int len=len1-len2;
if(len1<len2){
len=len2-len1; 找到长的链表,让长的链表移动他们差值步
cur1=headB;
cur2=headA;
}
while(len>0){
cur1=cur1.next;
len--;
}
while(cur1!=cur2){ 当不相等就往后走
cur1=cur1.next;
cur2=cur2.next;
}
if(cur1==cur2&&cur1!=null){ 这个时候他们肯定相等,如果不是null就返回cur1
return cur1;
}
return null;
}
}
八、第一个入环节点(拓展)
题目: 数学分析一下:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow=head;
ListNode fast=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(slow==fast)break;
}
if(fast==null||fast.next==null){ 找到第一次相遇的地方
return null;
}
slow=head; 让slow从新指向头
while(fast!=slow){ 以相同的速度前进知道下次相遇。
fast=fast.next;
slow=slow.next;
}
return slow; 第二次相遇的地方就是咱们的入口
}
}
九、再熟悉一下链表在ACM模式下的输入输出
static class ListNode{
public int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(){};
}
public static void main(String[] args) {
ListNode head=new ListNode();
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
ListNode cur=head;
int[]nums=new int[n];
for (int i = 0; i < n; i++) {
nums[i]=sc.nextInt();
}
for (int i = 0; i <n; i++) {
cur.next=new ListNode(nums[i]);
cur=cur.next;
}
ListNode nx=partition(head, 5);
ListNode px=nx.next;
while (px!=null){
if(px.next!=null){
System.out.print(px.val+" ");
px=px.next;
}
else{
System.out.println(px.val);
return;
}
}
}
|