鏈表
指定區域反轉
找到區間(頭和為 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 hereconst 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 herelet 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 hereconst 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 hereconst 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 herelet odd=head;//奇數let even=head.next;//偶數let evenHead=even;//記錄偶節點的頭結點//終止條件:偶節點&偶節點.next不為空!!!!//even&&even.nextwhile(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 herelet 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;
}