每日份学习分成三部分,leetcode算法,前端八股,休息&&整理每日学院的校招信息。
算法我不是很会,一般都是先自己思考,写不出来就会看答案,然后看懂答案。我用的是JS写算法,也会贴上一些我觉得写的比较好的博主的写法,如有侵权联系我。
1. 算法
- 两数之和
- 两数相加
- 无重复字符的最长子串
- 寻找两个正序数组的中位数
1.1 两数之和
题目描述:给定一个整数数组
nums
和一个整数目标值target
,请你在该数组中找出 和为目标值target
的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
思路:找一个元素x,并判断对应的target-x是否存在
解法1-暴力解法
遍历数组,得到和数组元素i相加等于target的数值y(y=target-num)。判断数组是否含有元素y,且元素下标不能等于num的下标。
// 暴力
var twoSum = function(nums, target) {
for(let i=0;i<nums.length;i++){
let x=target-nums[i]
let index=nums.indexOf(x)
if(index!==-1 && index!==i){
return [index,i]
}
}
return []
};
解法2--使用hash map
之前也没接触过hash map是什么,hash散列表是为了将计算机不连续的内存利用起来,这部分需要自己去了解。我就里就是记住了map是键值对形式,HashMap是键值唯一。
这里是一边将数据元素加入到HashMap中,一边判断HashMap是否存在让数组元素i相加等于target的数值x。就是把上面的方法换成了HashMap判断。因为
var twoSum = function(nums, target) {
let map =new Map();
for(let i=0;i<nums.length;i++){
let x=target-nums[i];
if(map.has(x)){
return [map.get(x),i]
}else{
map.set(nums[i],i)
}
}
return []
};
1.2 两数相加
题目描述:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
思路:直接按照加法列竖式的思想计算,但注意还要记录进位。因为最后返回链表,返回的头结点,所以还需要一个变量记录头结点位置。
解法1-暴力解法
new ListNode创建新节点,每次都要创建新节点来保存每个位上相加的值
var addTwoNumbers = function(l1, l2) {
// 定义一个新的节点,然后暴力循环解决
// let newHead=new ListNode() 创建新结点
// 进位数
let plus=0
// 结果
let result = new ListNode();
let head = result; //用来保存头结点
while(l1 || l2){
// 求和
let sum = ((l1 && l1.val) || 0) + ((l2 && l2.val) || 0) + plus
// 取整,直接使用 / 运算符得到的是小数
plus = Math.floor(sum / 10)
let value = sum % 10
result.next=new ListNode(value)
result=result.next
l1=l1 && l1.next
l2=l2 && l2.next
}
if(plus){
result.next=new ListNode(plus)
}
return head.next
};
1.3 无重复字符的最长子串
题目描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串的长度。
思路:使用滑动窗口
解法1-滑动窗口这也是力扣的官方解法
就是遍历字符串,将其放到新数组arr中,右边界一直移动,左边界不动。但当发现相同的元素之后,左边界的下标则改为这个第一次出现这个元素的位置,同时使用splice,删除这个元素前面的元素。记录每次数组arr的大小,并得到最大的。
var lengthOfLongestSubstring = function(s) {
let arr = [], max = 0
for(let i = 0; i < s.length; i++) {
let index = arr.indexOf(s[i])
if(index !== -1) {
arr.splice(0, index+1);
}
arr.push(s.charAt(i)) // arr.push(s[i])
max = Math.max(arr.length, max)
}
return max
};
解法2-使用set集合
考虑到set集合每个元素只出现一次,我使用的就是set集合。依次把字符元素加入到set集合中,但出现重复的时候,就将set置空,记录每次set的长度,从而得到最长的长度。
// 用set集合来判断,左边界依次是0,1,2,,n,通过set集合找到右边界
var lengthOfLongestSubstring = function(s) {
const set =new Set()
const n= s.length;
let ans=0
let max=0
let right =1
for(let i=0;i<n;i++){
set.add(s.charAt(i))
for(let j=i+1;j<n;j++){
if(set.has(s.charAt(j))){
ans=set.size
max=Math.max(max,ans)
set.clear()
break
}
set.add(s.charAt(j))
}
ans=set.size
max=Math.max(max,ans)
}
return max
};
1.4 寻找正序数组的中位数
题目描述:给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
解法1-暴力解法
将两个数组合并,排序,然后取中位数
var findMedianSortedArrays = function(nums1, nums2) {
// 合并数组
let nums=nums1.concat(nums2)
nums.sort((a,b)=>a-b)
let len=nums.length
if(len % 2 == 0){
// 偶数
return (nums[len/2]+nums[len/2-1])/2
}else{
// 奇数
return nums[Math.floor(len/2)]
}
};
解法2-双指针遍历
需要判断数组越界的情况
var findMedianSortedArrays = function(nums1, nums2) {
let len1=nums1.length;
let len2=nums2.length;
let point1=0,point2=0; // 数组下标
let value1=0,value2=0; // 数组下标对应的值
let len=nums1.length+nums2.length
for(let i=0;i<=Math.floor(len/2);i++){
value1=value2
if((point1 < len1) && (point2 >= len2 || nums1[point1] < nums2[point2])){
value2=nums1[point1]
point1++
}else{
value2=nums2[point2]
point2++
}
}
if(len%2==0){
return (value1+value2)/2
}else{
return value2
}
};
我看还有比较高级的解法,我就不深究了。
今日份算法总结
- HashMap
- Set
- 滑动窗口
// 1. HashMap
let map =new Map()
map.has(x) // 返回 false,true
map.get(x)
map.set(x,index)
// 2. set集合
let set=new set()
set.has()
set.add()
set.clear
set.size
let arr = [1,2,2,2,2,"2",24,5,6];
//step1:数组转集合
let set = new Set(arr);//已经去掉重复值,当前不是数组,而集合 Set { 1, 2, '2', 24, 5, 6 }
//step2:集合转数组
arr = [...set];//[ 1, 2, '2', 24, 5, 6 ]