题目描述
有 n
个盒子。给你一个长度为 n
的二进制字符串 boxes
,其中 boxes[i]
的值为 '0'
表示第 i
个盒子是 空 的,而 boxes[i]
的值为 '1'
表示盒子里有 一个 小球。
在一步操作中,你可以将 一个 小球从某个盒子移动到一个与之相邻的盒子中。第 i
个盒子和第 j
个盒子相邻需满足 abs(i - j) == 1
。注意,操作执行后,某些盒子中可能会存在不止一个小球。
返回一个长度为 n
的数组 answer
,其中 answer[i]
是将所有小球移动到第 i
个盒子所需的 最小 操作数。
每个 answer[i]
都需要根据盒子的 初始状态 进行计算。
EX1.
EX2.
提示
n == boxes.length
1 <= n <= 2000
boxes[i]
为'0'
或'1'
代码实现
C语言
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
//该函数返回的数组必须是内存动态分配定义的,假设在函数调用后,调用者会对该数组进行内存清理
int* minOperations(char* boxes, int* returnSize)
{
int i;
int j;//定义循环变量
int sum=0;//中间变量
int len;
len=strlen(boxes);//利用字符串函数strlen获得字符串boxes的长度
int* answer=(int*)malloc(sizeof(int)*len);//动态规划定义与boxes等长的返回数组
for(i=0;i<len;i++)//第一层循环遍历选定一个箱子
{
//原本的sum=0;在这,但为了程序可读性,移动到循环末尾,并在定义处进行初始化
for(j=0;j<len;j++)//当前箱子为基准,计算其他箱子的球调度到该箱子所需操作步数
{
if(i==j)//跳过计算当前箱子到当前箱子的调度过程
{
continue;//continue是跳过当次循环,执行下次,break是跳过当层循环,执行下一语句,这里只需跳过一次循环,而不是一重循环(有点绕...)
}
if(boxes[j]=='1')//这一判断语句要有,这一步卡了很久,待会细说
{
sum=sum+abs(i-j);//计算每个箱子到基准箱子所需的操作数,并加到总和
}
}
answer[i]=sum;//赋总和给answer的指定下标的元素
sum=0;//然后清空中间变量
}
*returnSize=len;//设置返回数组的大小,也就是boxes的大小
return answer;
}
思路
拿到题目,粗略读了一遍,大概过了一遍,脑子里大概想到了要用循环,具体几层?每层循环要干嘛?还不懂。细想了一下,感觉有点麻烦,要以每个箱子为对象,计算每个箱子到指定箱子需要的步数?感觉有点难实现。然后在纸质草稿纸上推演了一下,在循环里只需要计算每个箱子到指定箱子的下标之差(绝对值)就可以,然后再加一层循环,遍历每个指定箱子,大体思路就是这样,开动!大功告成,运行!报错!.......
原因错在哪?我貌似忽略了一点...boxes貌似是个字符串!不是int,如果需要直接用boxes的值来做运算,那你需要转换。这里我尝试了几个方法,一起来看看吧。
第一种:
(int)boxes[i];//编译成功,结果错误
原因是这样转换,‘1’得到的并不是1,而是‘1’的ASCII码,最后得出来数值偏大。
第二种:
int num=boxes[j]-'0';
sum=sum+num*abs(i-j);//编译成功,结果正确
这是百度搜出来的,学到的,如果不想用函数转换,也可以自己设计一个语法计算出来数值,当然如果可以封装成函数就更好了。(个人认为封装成函数泛化能力不强,只对0~9有效)
第三种:
boxes_copy=atoi(boxes);//不可行,下面分析
也是百度搜出来的,函数atoi()就是把字符串转换成一个整型数字,原理就是用一个新的整型变量来把boxes变成一个数,我一开始认为是可行的,原因是可以用这个整型数字,每次取一个固定位数,然后作为箱子中的球的有无,用循环可以实现,也能封装成函数,虽然麻烦,而且代价过高,但可行。
后面细想了一下还是有不少困难的,首先如何实现取指定位数?取第一位,最后一位固然方便,但如果是取中间的呢?还是只能用循环来敲定?个人认为还是比较困难,第二个是这个函数是把一个字符串转变成整型数,但如果这个字符串是00001呢?转换成整型数是1,那001?也是1?那转换前后不就有信息损失了嘛,所以综上归根到底还是不可行。
解决了上面困难这道题基本就结束了,然后提交就行,下面是反馈结果。
50+60,还行,但还能优化吗?下面看看题解区大佬的做法
C语言【题解区大佬】
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
#include<math.h>
#include<stdlib.h>
int* minOperations(char* boxes, int* returnSize) {
int a = strlen(boxes);
int* res = (int*)malloc(sizeof(int) * a);
int left = 0, right, num = 0;
int i;
for (i = 0;i < a;i++) {
res[i] = 0;
}
for (i = 0;i < a;i++) {
if (boxes[i] == '1') {
res[0] += i;
num++;
}
}
right = num;
for (i = 1;i < a;i++) {
if (boxes[i - 1] == '1') {
left++;
right--;
}
res[i] = res[i - 1] - right + left;
}
*returnSize = a;
return res;
}
//只能说根本看不懂...大佬的逻辑太强大了...
喂给AI喂了三次才勉强理解,大概就是
对于`boxes`中的每个1,我们更新左右边界(`left`和`right`)。`left`表示1左边的0的数量,`right`表示1右边的0的数量。对于每个位置,我们计算操作数为:前一个位置的操作数减去`right`(因为这些0不需要移动),再加上`left`(因为这些0需要移动到前面)。
还是太难懂了...先贴在这,以后大成了再回来看吧...顺便观摩一下大佬的80+95...
总结
还是拖到现在才收尾,8:51,刷力扣到底有什么收获呢?自学的困难要记住。今天看CSDIY的时候看到一句话很有感触。
自学的一大困难就是难以自律,你在自学算法的时候你会问自己,到底收获了什么?到底有什么用?看着身边人都在玩游戏,或者学数学,学英语,这一整个过程没有学分,没有绩点,没有老师,没有同学...但心中请秉持着这样一个信念:你在变强
还是回到题目本身,这道题学到的大概是一些思维的转换,有些细节末枝,关于数据类型的转换,希望以后有帮助。(明天要补课...)
顺便扯一些有的没的吧,还是希望自己能加强时间密度,放松的时候好好放松,卷的时候好好卷,期中考试成绩也出来了,在意料之中吧,但是看到一些上课从来不听的人居然比我高了差不多15分的时候还是很惊讶的...但....谁知道呢,怎么知道人家每天在宿舍不是在学习呢?当然,乾坤未定,你我皆是黑马。有一群喜欢学习,追求卓越的朋友也蛮好的。明天继续加油!