写在前面
周五面试酷家乐 面试官上来直接五道算法题把我给整懵了 记录一下吧 算法题还是要多刷多刷!
解法一 排序 不赘述了
解法二 利用map集合
var majorrityElement=function(nums){
let map=new Map();
for(let i=0;i<nums.length;i++){
if(!map.has(nums[i]))
map.set(nums[i],1);
else
map.set(nums[i],map.get(nums[i])+1)
for(let [key,value] of map.entries()){
if(value>nums.length/2)
return key;
}
}
//主要考察es6里面map的用法 set,get.包括map的遍历
解法三 投票算法
var majorityElement = function(nums) {
let count = 1;
let majority = nums[0];
for(let i = 1; i < nums.length; i++) {
if (count === 0) {
majority = nums[i];
}
if (nums[i] === majority) {
count ++;
} else {
count --;
}
}
return majority;
};
lleetcode84柱形图中最大的矩形
这个题目看到暴力肯定是能做的,当时想到了滑动窗口但是没做出来真的很可惜,这道题目不难的
//暴力枚举高
var largestRectangleArea = function(heights) {
var maxArea = 0;
var len = heights.length;
for(var i = 0;i < len;i++){
var left_i = i;
var right_i = i;
while(left_i >= 0 && heights[left_i] >= heights[i]){
left_i--;
}
while(right_i < len && heights[right_i] >= heights[i]){
right_i++;
}
maxArea = Math.max(maxArea,(right_i - left_i - 1) * heights[i])
}
return maxArea;
};
从枚举高的角度出发这个题目变成了如何当前柱子的左侧且最近的小于其高度的柱子
我们利用单调栈来解决
var largestRectangleArea = function(heights) {
if (!heights || !heights.length) return 0
heights.unshift(0), heights.push(0)
const stack = []
let maxArea = 0
for (let i = 0; i < heights.length; i++) {
while (stack.length && heights[ stack[stack.length - 1] ] > heights[i]) {
const j = stack.pop()
maxArea = Math.max(maxArea, ( i - stack[stack.length - 1] - 1 ) * heights[j] )
}
stack.push(i)
}
return maxArea
}
还是搞不太懂 只明白了 左右两次利用栈。。
第三题
()()()n对括号对排列组合
K = 1 => ()
K = 2 => (()), ()()
K = 3 => ((())), ()()(), (())(), ()(()), ...
实现 function bracket_arrange(k), 输出所有合法的排列结果
leetcode 22
var generateParenthesis = function (n) {
const res = [];
const dfs = (lRemain, rRemain, str) => { // 左右括号所剩的数量,str是当前构建的字符串
if (str.length == 2 * n) { // 字符串构建完成
res.push(str); // 加入解集
return; // 结束当前递归分支
}
if (lRemain > 0) { // 只要左括号有剩,就可以选它,然后继续做选择(递归)
dfs(lRemain - 1, rRemain, str + "(");
}
if (lRemain < rRemain) { // 右括号比左括号剩的多,才能选右括号
dfs(lRemain, rRemain - 1, str + ")"); // 然后继续做选择(递归)
}
};
dfs(n, n, ""); // 递归的入口,剩余数量都是n,初始字符串是空串
return res;
};
回溯的关键点
1 出口。一个递归算法一定要有出口,否则就是一个死循环了。出口语句一般都挺好写的,但 是出口语句该放在哪儿了,这个就是关键了,这儿容许我先卖个关子。
2 递归函数的参数。一般情况下,递归函数是要带参数的,因为递归操作都是用来处理下一次的过程,如果没有参数的话,那么就很难从下一次的操作回溯到当前操作了。这么说,可能会有点迷糊,别急,后面我会举例子,这儿还是卖个关子。
3 递归函数的处理过程。这个自不必多说,重中之重,需要好好理解其过程
leetcode 78.子集全排列 可以动态规划做
var subsets = function(nums) {
var len=nums.length;
var res=[[]];
var temp=[];
for(let i=0;i<nums.length;i++){
let temp=JSON.parse(JSON.stringify(res));
for(let j=0;j<res.length;j++){
res[j].push(nums[i]);
}
res=res.concat(temp);
}
return res;
};
正常的回溯
var subsets = function(nums) {
const t = [];
const ans = [];
const n = nums.length;
const dfs = (cur) => {
if (cur === nums.length) {
ans.push(t.slice());
return;
}
t.push(nums[cur]);
dfs(cur + 1, nums);
t.pop(t.length - 1);
dfs(cur + 1, nums);
}
dfs(0, nums);
return ans;
};
leetcode 112 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
const hasPathSum = (root, sum) => {
if (root == null) return false; // 遍历到null节点
if (root.left == null && root.right == null) { // 遍历到叶子节点
return sum - root.val == 0; // 如果满足这个就返回true。否则返回false
}
// 当前递归问题 拆解成 两个子树的问题,其中一个true了就行
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
剑指offer24 反转链表 不赘述了
leetcode 25
k个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。