1. 算法--双指针
1.1 移动零
题目描述:给定一个数组
nums
,编写一个函数将所有0
移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
解法1:删除0元素+尾部补0
遍历数组,当遇到0元素的时候,就把这个元素从数组中删除,并在数组的尾部补0。特别注意的是数组长度的变化,数组元素位置的变化,要i--,还要判断i===nums.length
参考:JavaScript 经典算法面试题 - 移动零_给定一个数组 nums,编程实现将数组中包含的所有 0 移动到数组的前面,同时保持非零-优快云博客
var moveZeroes = function(nums) {
// 0 的个数
let b = 0;
for (let i = 0; i < nums.length; i++) {
if(i === nums.length-b){
break;
}
if (nums[i] === 0) {
nums.splice(i, 1);
nums.push(0);
b++;
i--
}
}
};
解法2:非0数字左移,剩余置为0 + 双指针
双指针两次遍历。第一次遍历将所有的非0元素左移,并记录下0元素的个数,第二次遍历将数组后面的元素都置0。
var moveZeroes = function(nums) {
// 非0元素 的个数,非0元素应该存放的位置
let b= 0;
//第一次遍历,将所有的非零元素移到左边
for (let i = 0; i < nums.length; i++) {
if(nums[i]!=0){
nums[b]=nums[i];
b++;
}
}
// 将b下标开始的元素置0
for(let i=b ; i<nums.length; i++){
nums[i]=0
}
};
解法3:一次遍历+双指针
一个指针用来寻找非0元素,一个指针用来指向当前非0元素应该存放的位置。
var moveZeroes = function(nums) {
// 非0元素应该存放的位置
let b= 0;
for(let i=0;i<nums.length;i++){
if(nums[i]!=0){
let temp=nums[b]
nums[b]=nums[i]
nums[i]=temp
b++;
}
}
};
// 也可以这样,避免一些不必要的交换
var moveZeroes = function(nums) {
// b记录非0元素应该存放的位置
let b= 0;
for(let i=0;i<nums.length;i++){
if(nums[i]!=0){
// 这里加一个判断
if(nums[b]===0){
let temp=nums[b]
nums[b]=nums[i]
nums[i]=temp
}
b++;
}
}
};
1.2 盛最多水的容器
题目描述:给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
解法1:暴力解法
双重循环,第一重循环是左边界,第二重循环是右边界。
解法2:双指针移动短的一边
关于这个算法,其实我不太理解。但看到了一段话:移动短的一边是因为:如果移动长的一边,宽已经由短的一边固定了,长度在不断缩减,所以以后的面积只会比现在小;如果移动短的一边,即使长度变短了,但是宽度和长度的乘积可能会变大;最后就是将最大值返回。
注意:要先计算max后再移动指针
var maxArea = function(height) {
let leftPoint=0
let rightPoint=height.length-1;
let max=0
// 短的一边的高度
let minHeight=0
while(leftPoint<rightPoint){
minHeight = Math.min(height[leftPoint], height[rightPoint]);
max=Math.max(max,(rightPoint-leftPoint)*minHeight)
// 移动高度短的指针
if(height[leftPoint]>height[rightPoint]){
rightPoint--;
}else{
leftPoint++;
}
}
return max
};
1.3 三数之和
题目描述:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。
解法1:暴力解法
三重循环
解法2:双指针
先将数组进行排序,然后遍历nums[i],使用双指针找,左边为i+1,右边为len-1,求三者的和sum=nums[i]+nums[left]+nums[right],如果和小于0则左指针右移,如果和大于0则右指针左移,直到两者相遇。注意:可能会有重复的,要去重。
var threeSum = function(nums) {
nums.sort((a,b)=>a-b);
let res=[];
for(let i=0;i<nums.length;i++){
if(nums[i]>0) break;
if(nums[i]==nums[i-1]){
continue;
}
let left=i+1,right=nums.length-1
while(left<right){
// 也可以把去重放在这里
// if(nums[left]==nums[left+1]){
// left++
// continue
// }
// if(nums[right]==nums[right-1]){
// right--
// continue
// }
let sum=nums[left]+nums[right]+nums[i]
if(sum>0){
right--
}else if(sum<0){
left++
}else{
res.push([nums[i],nums[left],nums[right]]);
left++
right--
// 但是还要去重,[-2,0,0,2,2]这个例子
while(left<right && nums[left]==nums[left-1]) left++
while(left<right && nums[right]==nums[right+1]) right--
}
}
}
return res
};
总结
- 注意splice和slice函数的区别,一个是删除数组元素,插入数组元素,一个是截取数组
2. 前端八股
前端充电宝公众号
1. MVVM、MVC、MVP的区别
MVC、MVP 和 MVVM 是三种常见的软件架构设计模式。
MVC:M是数据层,负责和数据库进行交互,存取和操作数据;存储数据以及对数据的操作
V是视图,负责用户界面呈现,仅显示从Model获取的数据。
C是控制器,负责响应用户的操作。负责管理View到Model。
M和V之间是观察者模式,当Model变化时,通知View去更新。当用户与页面View产生交互的时候,通过调用 Model 层,来完成对 Model 的修改,然后 Model 层再去通知 View 层更新。
View-->Controller-->Model--->View
MVP: P是中介者,可以从Model获取数据并更新View
MVVM: M是数据模型,数据和业务逻辑都在Model层中定义
V是视图,负责展示页面
VM是负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作通过View来更新Model
面试鸭公众号
1. 为什么Vue中的data属性是函数而不是对象
2. Vue的template标签有什么作用
3. 心得
今天做了一家公司的笔试,让我觉得,以刷力扣为重点是本末倒置,应该主要是要背前端八股,背自己的项目经验