链表
指定区域反转
找到区间(头和为 for循环当**时)->反转链表(返回反转过后的头和尾)->连接
function reverseBetween( head , m , n ) {
//preEnd&cur&nextStart cur.next断开
if(m===n)return head;
const vHeadNode=new ListNode(0);
vHeadNode.next=head;
let preEnd=null;
let cur = vHeadNode;
for(let i=0;i<n;i++){
if(i===m-1)preEnd=cur;
cur=cur.next;
}
let nextStart =cur.next;
cur.next=null;
const [start,end]=reverseList(preEnd.next);
preEnd.next=start;
end.next=nextStart;
return vHeadNode.next;
}
function reverseList(head){
const vHeadNode=new ListNode(-1);
vHeadNode.next=head;
let cur=head;
while(cur){
const next=cur.next;
cur.next=vHeadNode.next;
vHeadNode.next=cur;
cur=next;
}
return [vHeadNode.next,head];
}
每K个一组反转(★★★)
指针preEnd&cur->while(cur)->curStart=cur;curEnd=preEnd,if(!preEnd)return vHead.next->反转连接-》cur=nextStart&preEnd=End(翻转过后)
function reverseKGroup(head, k) {
// write code here
const vHeadNode=new ListNode(-1);
vHeadNode.next=head;
let preEnd=vHeadNode;
let cur=head;
while(cur){
let curStart=cur;
let curEnd=preEnd;
for(let i=0;i<k;i++){
curEnd=curEnd.next;
if(!curEnd)return vHeadNode.next;
}
let nextStart=curEnd.next;
curEnd.next=null;
const [start,end]=reverseSubList(curStart);
preEnd.next=start;
end.next=nextStart;
cur=nextStart;
preEnd=end;
}
return vHeadNode.next;
}
//反思一下自己吧!!!简单但请仔细
function reverseSubList(head) {
let dummyNode = new ListNode(0);
let cur = head;
while (cur) {
let next = cur.next;
cur.next = dummyNode.next;
dummyNode.next = cur;
cur = next;
}
return [dummyNode.next, head];
}
合并K个已排序链表(★★★)
基础:合并两个已排序链表->归并排序
export function mergeKLists(lists: ListNode[]): ListNode {
// // write code here
// //nlogn --->归并
// //拆开
// //返回的是ListNode不是数组类型,ts编译会报错!太好了
// if(lists.length<=1) return lists[0];
// const mid=Math.floor(lists.length/2);
// const left=mergeKLists(lists.slice(0,mid));
// const right=mergeKLists(lists.slice(mid));
// return merge(left,right);
if(lists.length<=1)return lists[0];
const mid =Math.floor(lists.length/2);
const left = mergeKLists(lists.slice(0,mid));
const right=mergeKLists(lists.slice(mid));
return merge(left,right);
}
function merge(pHead1:ListNode, pHead2:ListNode) {
const dummyNode = new ListNode(0);
let cur = dummyNode;
while (pHead1 && pHead2) {
if (pHead1.val < pHead2.val) {
cur.next = pHead1;
pHead1 = pHead1.next;
} else {
cur.next = pHead2;
pHead2 = pHead2.next;
}
cur = cur.next;
}
cur.next=pHead1?pHead1:pHead2;
return dummyNode.next;
}
基础
//双指针判断是否有环
function hasCycle( head ) {
if(!head)return false;
//起点相同
let fast=head;
let slow=head;
//&&这里出错
while(fast&&slow&&fast.next){
//先跳后判断
fast=fast.next.next;
slow=slow.next;
if(fast===slow)return true;
}
return false;
}
//链表环的入口
function EntryNodeOfLoop(pHead)
{
if(!pHead||!pHead.next)return null;
let fast=pHead;
let slow=pHead;
while(fast&&slow&&fast.next){
fast=fast.next.next;
slow=slow.next;
if(fast===slow){
fast=pHead;
//这!!!
while(fast!==slow){
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
}
//倒数第 K个节点
function FindKthToTail( pHead , k ) {
// write code here
//测试案例II,求长度!
const genLen=(curNode)=>{
let count=0;
while(curNode){
curNode=curNode.next;
count++;
}
return count;
}
const len=genLen(pHead);
//判断是否合理!!!
if(k>len)return null;
let fast=pHead,slow=pHead;
while(k--){
fast=fast.next;
}
//这条件!!!
while(fast){
fast=fast.next;
slow=slow.next;
}
return slow;
}
//删除链表的倒数第n个节点(虚拟头结点)
function removeNthFromEnd( head , n ) {
// write code here
let vHeadNode=new ListNode(0);
vHeadNode.next=head;
let fast=vHeadNode;
let slow=vHeadNode;
while(n--){
fast=fast.next;
}
// //若不借助虚拟节点
// //这一步真是太关键了
// if(quick == null){
// return head.next
// }
//key:此处判断条件就不一样 fast.next&&slow.next!!!
while(fast.next){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return vHeadNode.next;
}
//两链表第一个公共节点
export function FindFirstCommonNode(pHead1: ListNode, pHead2: ListNode): ListNode {
//另一种思路:求长度差+先走+while相等退出返回
//循环条件应该是当两个指针没有相遇时继续循环,即while(cur1 !== cur2)。
//这样,当它们相等时(无论是相交节点还是都为null)就退出循环并返回cur1(此时等于cur2)
if(!pHead1||!pHead2)return null;
let cur1=pHead1;
let cur2=pHead2;
while(cur1!==cur2){
cur1=cur1?cur1.next:pHead2;
cur2=cur2?cur2.next:pHead1;
}
return cur2;
}
链表相加(★★★)
先反转+链表相加(大数相加)+反转结果
function addInList( head1 , head2 ) {
// write code here
const dummyNode=new ListNode(0);
let cur=dummyNode;
let reversedList1=reverseList(head1);
let reversedList2=reverseList(head2);
let carry=0;
while(reversedList1||reversedList2||carry){
let val1=reversedList1?reversedList1.val:0;
let val2=reversedList2?reversedList2.val:0;
const sum=val1+val2+carry;
const digit=sum%10;
const node =new ListNode(digit);
carry=Math.floor(sum/10);
cur.next=node;
cur=cur.next;
//!!!移动指针!!!链表相加肯定要移动指针!!!
if(reversedList1)reversedList1=reversedList1.next;
if(reversedList2)reversedList2=reversedList2.next;
}
return reverseList(dummyNode.next);
}
function reverseList(head){
let vHeadNode=new ListNode(0);
let cur=head;
while(cur){
let next=cur.next;
cur.next=vHeadNode.next;
vHeadNode.next=cur;
cur=next;
}
return vHeadNode.next;
}
单链表排序
分治(归并)排序
key:找链表中点(需借助虚拟头结点)->返回条件->合并(两个已排序链表)
function sortInList( head ) {
// write code here
//分治
if(!head||!head.next)return head;
const middle=findMiddle(head);
let right=middle.next;
middle.next=null;
const leftHead=sortInList(head);
const rightHead=sortInList(right);
const merge=(leftHead,rightHead)=>{
const dummyNode=new ListNode(0);
let cur=dummyNode;
let head1=leftHead;
let head2=rightHead;
while(head1&&head2){
if(head1.val>head2.val){
cur.next=head2;
head2=head2.next;
}else{
cur.next=head1;
head1=head1.next;
}
cur=cur.next;
}
cur.next=head1?head1:head2;
return dummyNode.next;
}
return merge(leftHead,rightHead);
}
function findMiddle(head){
//要虚拟头结点!!!!这一个函数错了,导致整个通过不了!!!
const dummyNode=new ListNode(0);
dummyNode.next=head;
let fast=dummyNode;
let slow=dummyNode;
while(fast&&fast.next){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
回文链表
找链表中节点(同上)-》反转左侧链表-》比较,若有不对等返回false
export function isPail(head: ListNode): boolean {
// write code here
const middle=findMiddle(head);
let leftHead=head;
let rightHead=middle.next;
middle.next=null;
const reverseList=(head:ListNode|null):ListNode=>{
const dummyNode=new ListNode(0);
let cur=head;
while(cur){
const next=cur.next;
cur.next=dummyNode.next;
dummyNode.next=cur;
cur=next;
}
return dummyNode.next;
}
let reverseRightHead=reverseList(rightHead);
while(leftHead&&reverseRightHead){
if(leftHead.val!==reverseRightHead.val)return false;
leftHead=leftHead.next;
reverseRightHead=reverseRightHead.next;
}
return true;
}
function findMiddle(head:ListNode):ListNode{
const dummyNode=new ListNode(0);
dummyNode.next=head;
let fast=dummyNode;
let slow=dummyNode;
while(fast&&fast.next){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
链表奇偶排序
指针:odd、even&evenHead
条件:even&&even.head
返回:head
function oddEvenList( head ) {
if(!head||!head.next)return head;
// write code here
let odd=head;//奇数
let even=head.next;//偶数
let evenHead=even;//记录偶节点的头结点
//终止条件:偶节点&偶节点.next不为空!!!!
//even&&even.next
while(even&&even.next){
odd.next=even.next;
odd=odd.next;
even.next=odd.next;
even=even.next;
}
odd.next=evenHead;
return head;
}
删除重复元素
I->cur=head
function deleteDuplicates( head ) {
// write code here
let cur=head;
//链表靠着时next指针,不要想着还计算长度什么!
while(cur){
while(cur.next&&cur.val===cur.next.val){
cur.next=cur.next.next;
}
cur=cur.next;
}
return head;
}
II(♥)
- 虚拟头结点
- 找到if(cur.next.val=cur.next.next.val)并存储至temp,内部while(cur.next&&cur.next.val=temp)删除节点
- 否则就是cur=cur.next
export function deleteDuplicates(head: ListNode): ListNode {
// // write code here
// const vHeadNode=new ListNode(0);
// vHeadNode.next=head;
// let cur=vHeadNode;
// let temp=0;
// while(cur.next&&cur.next.next){
// if(cur.next.val===cur.next.next.val){
// temp=cur.next.val;
// //相同的节点都跳过
// while(cur.next&&cur.next.val===temp){
// cur.next=cur.next.next;
// }
// }else{
// //其他节点就向后移
// cur=cur.next;
// }
// }
// return vHeadNode.next;
const vHeadNode=new ListNode(0);
vHeadNode.next=head;//虚拟头结点,解决第一个和第二个元素就相同的情况
let cur=vHeadNode;
let temp=0;
while(cur.next&&cur.next.next){
if(cur.next.val===cur.next.next.val){
temp=cur.next.val;
while(cur.next&&cur.next.val===temp){
cur.next=cur.next.next;
}
}else{
cur=cur.next;
}
}
return vHeadNode.next;
}