本周总共有7个题
周一
丑数
给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。
丑数 就是只包含质因数 2、3 和/或 5 的正整数。
链接:https://leetcode-cn.com/problems/ugly-number
/**@param {number} n@return {boolean}*/var isUgly = function(n) {//对N 取模,如果模为0在取商,如果2,3,5都取完了就看商是不是为1while(true){if(n<=0) return false //边界一开始最好就搞清楚if(n%2 === 0){n = n/2}else if(n%3 === 0){n = n/3}else if(n%5 =0){n = n/5}else{if(n=1){return true}else{return false}}}};
回文数
tips 这个题目是我加餐的,进阶要求是不能转为字符串来解决,第一周目我想仿照快慢指针来求解,但是其实只写出来一个半成品(看了官方解答,不是半成品,有些判定条件他自己也没有办法加进去)
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
链接:https://leetcode-cn.com/problems/palindrome-number
/**@param {number} x@return {boolean}*///1.23 n =2//123.123 -》123var isPalindrome = function(x) {//通过快慢指针找到中间点,反转let count = 0function findMiddleFunc(n){// 如果数字长度是偶数 结果是没有问题的,但是如果是奇数,就会有一位的偏差,该怎么修正//1122 fine//121 -> 1.21 vs 12.1let low = nlet fast = nwhile(fast >1){fast = fast/100low = low/10count ++}// console.log(low)return Math.floor(low)}function reverse(n){//反转数字let result = 0if(count ===0)return nwhile(count>0){//21120 是个坑count--result = result*10+ (n%10)n = Math.floor(n/10)// console.log(n)}// console.log(result)return result}// console.log(Math.floor(findMiddleFunc(x) ))// console.log(reverse(x))
//小于0直接判定 我一直希望能把这个判定写进两个函数里面,后面发现官方也是这么写的
if (x < 0 || (x % 10 === 0 && x !== 0)) {
return false;
}
//奇数和偶数长度判定
return findMiddleFunc(x)=== reverse(x) ||findMiddleFunc(x)=== Math.floor(reverse(x)/10 )
};
这个题目提交错误12次….
周二
丢失的数字
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
进阶:
你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?
链接:https://leetcode-cn.com/problems/missing-number
/**
- @param {number[]} nums
- @return {number}
/
var missingNumber = function(nums) {
//注意看题,给定一个包含[0,n]的n个数的数组 也就是说数组加上缺失的元素应该有 (n+1)个
// 解法求出总和 - 实际和
const n = nums.length
const total = n(n+1)/2
const actual = nums.reduce((pre,next)=>{return pre+next})
return total-actual
};
/** - @param {number[]} nums
- @return {number}
/
var missingNumber = function(nums) {
//使用异或+交换律
// a = 1 ^ 1^ 2=2
const n = nums.length
let curr = nums.reduce((pre,next)=>{
return pre ^next
})
for(let i = 0;i<=n;++i){
curr ^=i
}
return curr
};
周三
第一个错误的版本
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
链接:https://leetcode-cn.com/problems/first-bad-version
/* - Definition for isBadVersion()
- @param {integer} version number
- @return {boolean} whether the version is bad
- isBadVersion = function(version) {
...
};
*/
//[1,2,3..]这是一个顺序的数组,通过二分法可以有效的缩短
//之前的思路都是活动的middle
//看了官解之后选择[活动的边界]
/**
- @param {function} isBadVersion()
- @return {function}
/
var solution = function(isBadVersion) {
/*- @param {integer} n Total versions
- @return {integer} The first bad version
/
//初始边界值是1,n
return function(n) {
let left = 1
let right = n
let middle = null
while(leftmiddle = Math.floor((left +(right-left)/2)) //这个计算方法很妙,我都是直接左右和/2,他这个是以左边点为
//出发点加上差值一半,当时看官解说是防溢出,也就是左右的和过大
if(isBadVersion(middle)){
//中间是坏版本,那么就得在 left -middle中找
right = middle
}else{
//不是就得在中间之后的一位和right中找
left = middle+1
}
}
return left
};
};
周四
移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
https://leetcode-cn.com/problems/move-zeroes/
/*
- @param {number[]} nums
- @return {void} Do not return anything, modify nums in-place instead.
/
var moveZeroes = function(nums) {
//第一种解法数组一边shift() 一边 push
let len = nums.length
let count = 0
let curr = null
for(let i =0;icurr = nums.shift()
if(curr === 0 ){
count
}else{
nums.push(curr)
}
}
while(count>0){
nums.push(0)
count—
}
return nums
};
/* - @param {number[]} nums
- @return {void} Do not return anything, modify nums in-place instead.
/
var moveZeroes = function(nums) {
//使用快慢指针
//我其实没想到这种题可以使用快慢指针 表示下标
const len = nums.length
let fast = 0 //去寻找非0元素
let low = 0 //始终指向第一个0的位置
while(fastif(nums[low] !==0){
fast++
low++
}else if(nums[fast] === 0){//low指向第一个0,但是fast还没有找到非0
fast++
}else{//找到了
[nums[low],nums[fast]] = [nums[fast],nums[low]]
//对调完成
low++
fast++
}
}
return nums
};
周五
单词规律
给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。
链接:https://leetcode-cn.com/problems/word-pattern
/* - @param {string} pattern
- @param {string} s
- @return {boolean}
*/
var wordPattern = function(pattern, s) {
//双hash标
const patternMap = new Map()
const patternArray = […pattern]
const sMap = new Map()
const sArray = s.split(‘ ‘)
if(patternArray.length !== sArray.length) return false
patternArray.forEach((item,index)=>{
// a —0
// b —1
if(!patternMap.has(item)){
patternMap.set(item,index)
}
})
sArray.forEach((item,index)=>{
//dog —0
//cat —1
if(!sMap.has(item)){
sMap.set(item,index)
}
})
for(let i = 0;i
if( sArray[patternMap.get(patternArray[i])] !==sArray[i]){
return false
}
if(patternArray[sMap.get(sArray[i])] !==patternArray[i]){
return false
}
}
return true
};
脑袋晕乎乎的,这个题的多解法暂时不看了
周六
你和你的朋友,两个人一起玩 Nim 游戏:
桌子上有一堆石头。
你们轮流进行自己的回合,你作为先手。
每一回合,轮到的人拿掉 1 - 3 块石头。
拿掉最后一块石头的人就是获胜者。
假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true;否则,返回 false 。
https://leetcode-cn.com/problems/nim-game/
/**
- @param {number} n
- @return {boolean}
*/
var canWinNim = function(n) {
//第一个想法是递归,假设最后一个石头是你拿的,那么推回来第一次你拿的石油能否在1-3
// 但是我看这个题目应该是个动态规划的题目
//数学规律 1,2,3 win 4,lose 5,6,7win ,8lose
// if(n<=3) return true
if(n%4 ==0){
return false
}else{
return true
}
};
//此处需要补充一个动态规划的解法,但是我要去看电影了哈哈,明天在看
动态方程:
这个题目第一眼就是要是用动态方程求解,虽然我看到题解当中很多人都说超时
动态的步骤是:
1.递归+记忆化 ->递推
2.状态的定义:opt[n],dp[n],fib[n]
定义成一个数组
3.状态转移方程: opt[n] = best_of( opt[n-1],opt[n-2],…..) DP方程
1.先手对应 n 个石头,后面肯定对应 n-1 /n-2 /n-3个石头
从最后一步分析,如果先手剩余1-3个石头,那先手取得胜利/剩余0个个石头先手失败
所以递推关系
Fn = F(n-1)
倒数第二手的三种解法都失败了,倒数第一手才会成功
f(n) = !( f(n-1) && f(n-2) && f(n-3)) /这里也可以写成 !f(n-1) && !f(n-2) && !f(n-3)
f(0) = false
function canWinNim(n){
if(n<=3){
return true
}
return !(canWinNim(n-1) && canWinNim(n-2) && canWinNim(n-3))
}
当然,这里最后测试的结果是超时,但是我只是因为不记得动态规划所以复习一下
