目录
215.找第k大元素
三路的快速排序
快速选择
法2.堆选
(堆排序)
11.盛更多水的容器
代码1
代码2
560.和为K的子数组(题意!)
惯性思维
正解
21.合并生序链表
递归写法
128.最长连续序列
20.有效的括号
面试的时候不好好审题,太急,直接惯性思维用三个栈了
121.买卖股票的最佳时机
那么这道题想要时间复杂度低,肯定是不能全部排序的
先来讲讲
三路快排在两路的基础上加上了=的部分,
为了处理全部元素相同的特殊情况
总的来说就是通过三个指针维护 左边<、中间=、右边>
如下图的左上角所示
JS代码如下
function quickSort3Way(arr, left = 0, right = arr.length - 1) {
if (left >= right) return;
let lt = left; // 小于区域的右边界
let gt = right; // 大于区域的左边界
let pivot = arr[left]; // 选取第一个元素为基准
let i = left + 1; // lt 至 gt 中、=pivot右边、的当前正在判断的位置
while (i <= gt) {
if (arr[i] < pivot) {
[arr[lt], arr[i]] = [arr[i], arr[lt]];
lt++;
i++;
//原本lt位置是=pivot的,所以<分支中可以直接i++判断下一个
} else if (arr[i] > pivot) {
[arr[i], arr[gt]] = [arr[gt], arr[i]];
gt--;
} else {
i++;
//而gt位置是未知的,不能i++
}
}
quickSort3Way(arr, left, lt - 1);
quickSort3Way(arr, gt + 1, right);
}
let nums = [3, 5, 2, 3, 1, 3, 4, 2, 3];
quickSort3Way(nums);
console.log(nums);
注意:
//原本lt位置是=pivot的,所以<分支中可以直接i++判断下一个
//而gt位置是未知的,不能i++
快速选择就是在快速排序的基础上,对于最后的部分进行判断分支剪枝,从而只进行必要的排序
if (k_smallset
JS中没有内置堆模块,python自带了,而且还有两个(heapq、PriorityQueue)
通过最小堆找第k大(用最大堆的话得维护所有元素且弹k次)
将数组压入堆,维护至最大的k个元素(有多于k个:弹出最小的也就是弹出堆顶),那么堆顶就是第k大
import heapq
def findKthLargest(nums, k):
heap = []
for num in nums:
heapq.heappush(heap, num)
if len(heap) > k:
heapq.heappop(heap)
return heap[0]
堆排序就是一直 heappop
import heapq
def heap_sort(nums):
heapq.heapify(nums) # O(n) 建堆
res = [heapq.heappop(nums) for _ in range(len(nums))]
return res
var maxArea = function(height) {
let ans=0;
for(let l=0;ll){
if (height[r]>hnow){
ans=Math.max(ans,(r-l)*Math.min(height[l],height[r]));
hnow=height[r];
}
r--;//方向会影响
}
}
return ans;
};
上面我的第一次贪心效果并不是很好
实际上:由于双指针往中间时 d小了,只有 h大 才可能S大
只需要在 h 更大的时候才需要更新 ans
具体细节:短板效应-那边更小动那边
var maxArea = function(height) {
let ans = 0, left = 0, right = height.length - 1;
while (left < right) {
const area = (right - left) * Math.min(height[left], height[right]);
ans = Math.max(ans, area);
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return ans;
};
var maxArea=function(height){
let l=0;
let r=height.length-1;
let lh=height[l];
let rh=height[r];
let ans=(r-l)*Math.min(lh,rh);
while(llh){
lh=lnow;
ans=Math.max(ans,(r-l)*Math.min(lh,rh));
}
}else{
r--;
rnow=height[r];
if(rnow>rh){
rh=rnow;
ans=Math.max(ans,(r-l)*Math.min(lh,rh));
}
}
}
return ans;
}
看上去代码能节省更新 ans 的次数,但是实际上 代码1更快
简洁的代码更强健
不急
上来就写了一发DFS,但是题意是连续子数组
var subarraySum = function(nums, k) {
let ans = [];
function dfs(step, sum, choice) {
if (sum === k) {
ans.push([...choice]); // 通过展开运算符,拷贝,避免后续更改
}
if (step === nums.length) {
return;
}
choice.push(nums[step]);
dfs(step + 1, sum + nums[step], choice);
choice.pop(); // 直接pop,恢复现场
dfs(step + 1, sum, choice);
}
dfs(0, 0, []);
return ans;
};
连续:前缀和
通过 哈希表 优化:找目标
var subarraySum = function(nums, k) {
let count = 0;
let sum = 0;
let map = new Map();
map.set(0, 1); // 前缀和为0出现1次
for (let num of nums) {
sum += num;
if (map.has(sum - k)) {
count += map.get(sum - k);
}
map.set(sum, (map.get(sum) || 0) + 1);
}
return count;
};
(map.get(sum) || 0) 通过或语句将未出现时的 undifined 转为 0
一看就是双指针
注意力扣的链表类
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
当最后一方没有时,返回另一方,直接接在答案后面即可
var mergeTwoLists = function(l1, l2) {
if (l1 === null) {
return l2;
} else if (l2 === null) {
return l1;
} else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
};
复杂度比下面的迭代要好
var mergeTwoLists = function(l1, l2) {
const prehead = new ListNode(-1);
let prev = prehead;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
prev.next = l1;
l1 = l1.next;
} else {
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
prev.next = l1 === null ? l2 : l1;
return prehead.next;
};
Set去重后
通过哈希表判断连续
var longestConsecutive=function(nums){
const st=new Set(nums);
let ans=0;
for(const x of st){//注意下面用的都是st
if(st.has(x-1)){
continue;//上一个一定已经判断过了
}
let y=x+1;
while(st.has(y)){
y++;
}
ans=Math.max(ans,y-x);
}
return ans;
}
但是这怎么能三个栈呢,题目里面说了是正确的闭合,也就是 [ ( ] ) 是错的
直接开一个就够了
然后用哈希表优化逻辑
var isValid = function(s) {
if (s.length % 2) { // s 长度必须是偶数
return false;
}
const mp = {'(': ')', '[': ']', '{': '}'};
const st = [];
for (const c of s) {
if (mp[c]) { // c 是左括号
st.push(mp[c]); // 入栈
} else if (st.length === 0 || st.pop() !== c) { // c 是右括号
return false; // 没有左括号,或者左括号类型不对
}
}
return st.length === 0; // 所有左括号必须匹配完毕
};
维护之前最小值这一变量
var maxProfit = function(prices) {
let ans=0;
let min=prices[0];
for(let i=1;i