前言
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
参加周赛也有了一段时间了,奈何,成绩每况愈下,一发不可收拾,总结一下。
题目
第一题
链接:6249. 分割圆的最少切割次数 - 力扣(LeetCode)
题解:
是我唯一作对的一道🤦♀️
其实思路还是很明确的,因为他所有切割都是经过圆点的
-
假如切出来是偶数,那么直接按照直径去切就可以了
-
假如是奇数,那么就按照半径切,有几次切几次
-
但是注意1的情况
代码
/**
* @param {number} n
* @return {number}
*/
var numberOfCuts = function(n:number) {
// 如果n为奇数
if(n%2){
if(n === 1){
return 0
}
return n
}else{
return n/2
}
};
第二题
链接:6277. 行和列中一和零的差值 - 力扣(LeetCode)
最初的想法:
-
因为题目要求,判断0和1在各行各列的插值
-
所以我就可以计算出,每一行和列有多少个
1 -
然后
row+col减去1的行列总数,得到0的行列总数 -
判断两个的差值
代码:
/**
* @param {number[][]} grid
* @return {number[][]}
*/
// 通过异或判断
var xo = (num) => {
let count = 0;
while (num) {
if (num & 1) {
count++
}
num = num >> 1;
}
return count
}
var onesMinusZeros = function (grid) {
//这一行和列1的个数-这一行和列0的个数
let col = grid[0].length;
let row = grid.length;
//记录行里面多少个1
let countRow = []
//记录列里面多少个1
let countCol = []
let res = []
//计算一行里有多少个1
for (let value of grid) {
// let num = parseInt(value.join("")).toString(2)
let num = Number.parseInt(value.join(""),2)
console.log("行num",num)
countRow.push(xo(num))
}
console.log("行的1",countRow)
// 计算一列里面有多少个1
for (let i = 0; i < col; i++){
let num = "";
for (let j = 0; j < row; j++){
num += grid[j][i];
}
console.log("列num",num)
countCol.push(xo(parseInt(num,2)))
}
console.log("列的1",countCol)
for (let i = 0; i < row; i++){
let temp = []
for (let j = 0; j < col; j++){
let count1 = countRow[i] + countCol[j];
let count0 = row+col - count1;
temp.push(count1-count0)
}
res.push(temp)
}
return res
};
总结:
- 其实思路并没有什么问题
- 但是问题在于,数据量太大了,太多的for循环,消耗量太多的时间
- 而且,找不到比较好的,获取一个列的数据的方法
新的思路:
观看了一位UP主的视频,【力扣双周赛 92】前后缀分解_哔哩哔哩_bilibili
- 这是一道模拟题
- 他将
diff[i][j] = onesRowi + onesColj - zerosRowi - zerosColj - 理解为了
diff[i][j] = onesRowi - zerosRowi + onesColj - zerosColj - 其实他是在计算一行和一列里
1和0的差是多少 - 巧妙的点在于,他是将
1变为1,将0变为-1 - 这样的话,
-1+1=0,多出来没有消掉的就是,差的值 - 下次,我们只需要将当前
Row+Col,就可以知道总的差是多少了
代码:
/**
* @param {number[][]} grid
* @return {number[][]}
*/
var onesMinusZeros = function (grid:number[][]) {
//这一行和列1的个数-这一行和列0的个数
let Row = Array<number>(grid.length).fill(0)
let Col = Array<number>(grid[0].length).fill(0);
for( const [i,row] of grid.entries()){
// i就是下标,从0开始,一直到grid.length
// row其实是一个数组,表示每一行的数
for(const [j,value] of row.entries()){
// j也是下标,表示grid[0].length,value表示的是,当前这个值
Row[i] += value*2-1;//不使用判断,将1变为1,0变为-1
Col[j] += value*2-1;
}
}
console.log("col",Col)
console.log("row",Row)
// 现在这个数组,是由1和-1组成的
// 对这个数组进行遍历
for(const [i,x] of Row.entries()){
for(const [j,y] of Col.entries()){
grid[i][j] = x+y;
}
}
return grid
};
第三题
链接:6250. 商店的最少代价 - 力扣(LeetCode)
想法:
我第一题大概花了7分钟写完,害,磨磨唧唧的。
第二题,因为总觉得自己没写错,有想不到更好的方法,基本耗时有一个小时左右,🤷♀️。
给到第三题的时间也只有40分钟左右,后来题目都没看明白,代价分为哪几个部分
思路:
- 首先必须明确,在
i时间关门的代价是- 代价
i=i之前N的数量+i之后Y的数量
- 代价
- 所以我们可以实现一个函数来计算
Y的个数,这样N也就可以知道 - 然后比较,最小时间
代码:
function bestClosingTime(customers: string): number {
// 首先我们需要明确的是
// i的代价 = 在i之前的N的数量和在i之后的Y的数量
// 首先我们需要一个函数,来计算当前有多少个Y
// 首先计算有多少个Y
let SumY = countY(customers);
let str = "";
// let res = [SumY]
let min = SumY;
let minIndex = 0;
for(let i = 0;i<customers.length;i++){
str += customers[i]
let leftY = countY(str)
let leftN = (i+1)-leftY
let rightY = SumY-leftY
// res.push(leftN+rightY)
if(min > leftN+rightY){
minIndex = i+1;
min = leftN+rightY
}
}
return minIndex
};
const countY = (openTime:string):number=>{
let count = 0;
for(let value of openTime){
if(value === "Y"){
count++
}
}
return count
}
// const findMin = (arr:number[]):number=>{
// let min = arr[0];
// let index = 0;
// for(let [i,value] of arr.entries()){
// if(min > value){
// min = value;
// index = i
// }
// }
// return index
// }
起初,我是打算用数组来承接所有的代价,然后找出最早的最小的,但是超时了
现在,我直接用一个min变量直接承接,但是,还是超时🤦♀️
累了
---------11.29更新一下---------------
看了UP主的解题视频,非常巧妙,直接将复杂度降到了O(n)
他是这么分析的
- 首先在
0位置关门的话,那么我的代价其实就是,所有的Y的个数 - 那么我假设最小的代价
min_count,就是在第0个位置产生 - 然后向后遍历
- 假如我遇到了
Y- 那么也就是,刚好在这个时候,有顾客到来,那么代价
count减1 - 这时候就可能会出现最小代价,那么判断,更新数据
- 因为需要返回下标,所以,我们需要一个变量
index来承接下标
- 那么也就是,刚好在这个时候,有顾客到来,那么代价
- 假如我遇到了
N- 也就是,我开门的时候,没有顾客到来
- 那么代价+
1 - 也就不可能出现最小代价
min_count
- 假如我遇到了
- 注意:这边的下标其实需要+1,这是因为,因为遍历是从0开始的,但是,题目其实是从-1开始的,所以,需要+1
代码:
function bestClosingTime(customers: string): number {
// 首先我们需要明确的是
// i的代价 = 在i之前的N的数量和在i之后的Y的数量
// 首先我们需要一个函数,来计算当前有多少个Y
// 首先计算有多少个Y
let SumY = countY(customers);
// 因为要求最小值,所以维护一个最小值
let count = SumY;
let min_count = count;
// 设置一个下标,到时候输出答案
let index = 0;
for(let i = 0;i<customers.length;i++){
if(customers[i] === "Y"){
// 那就说明,现在是有顾客的,并且门也是开着的
// 代价-1
count--;
// 这时候可能产生的最小代价,那么随之而来的是,下标也要变化
// min_count = Math.min(min_count,count);
if(count <min_count){
index = i+1;
min_count = count
}
}else{
// 如果当前是N,也就是关门
// 那么也就是,我开店的时候,没有顾客来,那么代价加1
count++
// 因为count++,也不可能出现,最小count,所以,后面无需判断
}
}
return index
};
const countY = (openTime:string):number=>{
let count = 0;
for(let value of openTime){
if(value === "Y"){
count++
}
}
return count
}
第四题
困难题,我现在不强求自己会,先把基本题目看对再说吧
总结
-
对模拟的题目不是很了解,需要多多练习
-
思路打不开,一些方法比较巧妙,想不到啊