一、双链表实现双端队列
双端队列为一个队列既可以从头部实现节点的弹入弹出操作,也可以实现从尾部的弹入弹出操作,而想要实现这样的一个双端队列,就得用到链表结构。通过链表的last,next指针,来进行头尾弹入弹出的操作。
时间复杂度O(1)
public class DoubleLinkedListToDeque {
//创建节点类
public static class Node<V>{
public V value;
public Node<V> last;
public Node<V> next;
public Node(V v) {
value=v;
last=null;
next=null;
}
}
//创建队列类
public static class MyDeque<V> {
private Node<V> head;
private Node<V> tail;
private int size;
public MyDeque(){
head=null;
tail=null;
size=0;
}
public boolean isEmpty() {
return size==0;
}
public int size() {
return size;
}
//头部入队
public void pushHead(V v){
Node<V> cur=new Node<>(v);
if (head==null){
head=cur;
tail=cur;
}else{
cur.next=head;
head.last=cur;
head=cur;
}
size++;
}
//尾部入队
public void pushTail(V v) {
Node<V> cur=new Node<>(v);
if (head==null) {
head=cur;
tail=cur;
}else {
cur.last=tail;
tail.next=cur;
tail=cur;
}
size++;
}
//头部弹出
public V pollHead() {
V ans=null;
if (head==null){
return ans;
}
size--;
ans=head.value;
if (head==tail){
head=null;
tail=null;
}else {
head=head.next;
head.last=null;
}
return ans;
}
//尾部弹出
public V pollTail(){
V ans=null;
if (head==null){
return ans;
}
size--;
ans=tail.value;
if (head==tail) {
head=null;
tail=null;
}else {
tail=tail.last;
tail.next=null;
}
return ans;
}
//头部只弹出值
public V peekHead(){
V ans=null;
if (head!=null){
ans=head.value;
}
return ans;
}
//尾部只弹出值
public V peekTail(){
V ans=null;
if (head==null) {
ans=tail.value;
}
return ans;
}
}
}
二、K个节点的组内逆序调整
给链表的头节点 head ,每 k 个节点一组进行翻转,返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,将最后剩余的节点保持原有顺序。
不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
通过不断扣边界,搭配指针的来回跳转来实现。
//K个节点的组内逆序调整
public class ReverseNodesInKGroup {
//不用提交
public static class ListNode {
public ListNode next;
}
public static ListNode reverseKGroup(ListNode head,int k) {
ListNode start=head;
ListNode end=getKGroupEnd(start,k);
if (end==null) {
return head;
}
head=end;
reverse(start,end);
//标记上一组的结尾节点
ListNode LastEnd=start;
while (LastEnd.next!=null) {
start=LastEnd.next;
end=getKGroupEnd(start,k);
while (end==null) {
return head;
}
reverse(start,end);
LastEnd.next=end;
LastEnd=start;
}
return head;
}
public static ListNode getKGroupEnd(ListNode start,int k) {
while (--k!=0 && start!=null) {
start=start.next;
}
return start;
}
public static void reverse(ListNode start,ListNode end) {
end=end.next;
ListNode pre=null;
ListNode cur=start;
ListNode next=null;
while (cur!= end){
next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
start.next = end;
}
}
三、两链表相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
将两个数相加,并以相同形式返回一个表示和的链表。
假设除了数字 0 之外,这两个数都不会以 0 开头。
首先需要先确定一下这两个链表哪个是长链表,哪个是短链表,然后通过节点相加重新存值到长链表中,不用再开辟额外整个链表空间。
因为相加涉及到两数和的进位,所以需要设置三次判断,第一次循环短链表是否走到null,第二次循环长链表是否走到null,第三次判断长短链表是否还有进位数,三次判断确定两链表和的值。
public class AddTwoNumbers {
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val=val;
}
public ListNode(int val,ListNode next) {
this.val=val;
this.next=next;
}
public static ListNode addTwoNumbers(ListNode head1,ListNode head2) {
int len1=listLength(head1);
int len2=listLength(head2);
ListNode l=len1>=len2?head1:head2;
ListNode s=l==head1?head2:head1;
ListNode curL=l;
ListNode curS=s;
ListNode last=curL;
int carry=0;
int curNum=0;
//第一次循环判断
while (curS!=null) {
curNum=curL.val+curS.val+carry;
curL.val=curNum%10;
carry=curNum/10;
last=curL;
curL=curL.next;
curS=curS.next;
}
//第二次循环判断
while (curL!=null){
curNum=curL.val+carry;
curL.val=curNum%10;
carry=curNum/10;
last=curL;
curL=curL.next;
}
//第三次判断
if (carry!=0){
last.next=new ListNode(1);
}
return l;
}
public static int listLength(ListNode head) {
int len=0;
while (head!=null) {
head=head.next;
len++;
}
return len;
}
}
}
四、两个有序链表的合并
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
合并有序链表,首先需要确定一个较小的head,然后通过不断比较两两节点之间值,来确定上节点的next指针指向哪一个节点,从而做到合并且有序。
public class MergeTwoSortedLinkedList {
public static class ListNode {
public int val;
public ListNode next;
}
public static ListNode mergeTwoLists(ListNode head1,ListNode head2){
if(head1==null||head2==null){
return head1==null?head2:head1;
}
ListNode head=head1.val<=head2.val?head1:head2;
ListNode cur1=head.next;
ListNode cur2=head==head1?head2:head1;
ListNode pre=head;
while (cur1!=null&&cur2!=null) {
if (cur1.val<=cur2.val){
pre.next=cur1;
cur1=cur1.next;
}else {
pre.next=cur2;
cur2=cur2.next;
}
pre=pre.next;
}
pre.next=cur1!=null?cur1:cur2;
return head;
}
}
部分题目来源于 LeeCode