1、得到0的操作数
给你两个 非负 整数 num1 和 num2 。
每一步 操作 中,如果 num1 >= num2 ,你必须用 num1 减 num2 ;否则,你必须用 num2 减 num1 。
例如,num1 = 5 且 num2 = 4 ,应该用 num1 减 num2 ,因此,得到 num1 = 1 和 num2 = 4 。然而,如果 num1 = 4且 num2 = 5 ,一步操作后,得到 num1 = 4 和 num2 = 1 。
返回使 num1 = 0 或 num2 = 0 的 操作数 。
示例 1:
输入:num1 = 2, num2 = 3
输出:3
解释:
- 操作 1 :num1 = 2 ,num2 = 3 。由于 num1 < num2 ,num2 减 num1 得到 num1 = 2 ,num2 = 3 - 2 = 1 。
- 操作 2 :num1 = 2 ,num2 = 1 。由于 num1 > num2 ,num1 减 num2 。
- 操作 3 :num1 = 1 ,num2 = 1 。由于 num1 == num2 ,num1 减 num2 。
此时 num1 = 0 ,num2 = 1 。由于 num1 == 0 ,不需要再执行任何操作。
所以总操作数是 3 。
解答:
class Solution {
public:
int countOperations(int num1, int num2) {
int count=0;
while(num1!=0 && num2!=0)
{
if(num1>num2)
{
count+=1;
num1=num1-num2;
}
else
{
count+=1;
num2=num2-num1;
}
}
return count;
}
};
参考答案:
辗转相除
class Solution {
public:
int countOperations(int num1, int num2) {
int res = 0; // 相减操作的总次数
while (num1 && num2) {
// 每一步辗转相除操作
res += num1 / num2;
num1 %= num2;
swap(num1, num2);//交换函数
}
return res;
}
};
2、还原排列的最少操作步数
给你一个偶数 n ,已知存在一个长度为 n 的排列 perm ,其中 perm[i] == i(下标 从 0 开始 计数)。
一步操作中,你将创建一个新数组 arr ,对于每个 i :
如果 i % 2 == 0 ,那么 arr[i] = perm[i / 2]
如果 i % 2 == 1 ,那么 arr[i] = perm[n / 2 + (i - 1) / 2]
然后将 arr 赋值给 perm 。
要想使 perm 回到排列初始值,至少需要执行多少步操作?返回最小的 非零 操作步数。
示例 1:
输入:n = 2
输出:1
解释:最初,perm = [0,1]
第 1 步操作后,perm = [0,1]
所以,仅需执行 1 步操作
参考答案:
class Solution {
public:
int reinitializePermutation(int n) {
vector<int> vec(n), next(n);
for(int i = 0; i < n; ++i) vec[i] = i;
for(int i = 0; i < n; ++i){
if(i % 2 == 0) next[i] = vec[i / 2];
else next[i] = vec[n / 2 + (i - 1) / 2];
}
int ans = 0, cur = 1;
do{
ans++;
cur = next[cur];
} while(cur != 1);
return ans;
}
};
3、是数组元素相等的减少操作次数
给你一个整数数组 nums ,你的目标是令 nums 中的所有元素相等。完成一次减少操作需要遵照下面的几个步骤:
找出 nums 中的 最大 值。记这个值为 largest 并取其下标 i (下标从 0 开始计数)。如果有多个元素都是最大值,则取最小的 i 。
找出 nums 中的 下一个最大 值,这个值 严格小于 largest ,记为 nextLargest 。
将 nums[i] 减少到 nextLargest 。
返回使 nums 中的所有元素相等的操作次数。
示例 1:
输入:nums = [5,1,3]
输出:3
解释:需要 3 次操作使 nums 中的所有元素相等:
1. largest = 5 下标为 0 。nextLargest = 3 。将 nums[0] 减少到 3 。nums = [3,1,3] 。
2. largest = 3 下标为 0 。nextLargest = 1 。将 nums[0] 减少到 1 。nums = [1,1,3] 。
3. largest = 3 下标为 2 。nextLargest = 1 。将 nums[2] 减少到 1 。nums = [1,1,1] 。
参考答案:
class Solution:
def reductionOperations(self, nums: List[int]) -> int:
nums.sort()
n = len(nums)
res = 0 # 总操作次数
cnt = 0 # 每个元素操作次数
for i in range(1, n):
if nums[i] != nums[i-1]:
cnt += 1
res += cnt
return res
4、三维形体的表面积
给你一个 n * n 的网格 grid ,上面放置着一些 1 x 1 x 1 的正方体。每个值 v = grid[i][j] 表示 v 个正方体叠放在对应单元格 (i, j) 上。
放置好正方体后,任何直接相邻的正方体都会互相粘在一起,形成一些不规则的三维形体。
请你返回最终这些形体的总表面积。
注意:每个形体的底面也需要计入表面积中。
示例 1:
输入:grid = [[1,2],[3,4]]
输出:34
示例 2:
输入:grid = [[1,1,1],[1,0,1],[1,1,1]]
输出:32
参考答案:
分步累加
class Solution:
def surfaceArea(self, grid: List[List[int]]) -> int:
N = len(grid)
ans = 0
for r in range(N):
for c in range(N):
if grid[r][c]:
ans += 2
for nr, nc in ((r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)):
if 0 <= nr < N and 0 <= nc < N:
nval = grid[nr][nc]
else:
nval = 0
ans += max(grid[r][c] - nval, 0)
class Solution {
public:
int surfaceArea(vector<vector<int>>& grid) {
int dr[]{0, 1, 0, -1};
int dc[]{1, 0, -1, 0};
int N = grid.size();
int ans = 0;
for (int r = 0; r < N; ++r) {
for (int c = 0; c < N; ++c) {
if (grid[r][c] > 0) {
ans += 2;
for (int k = 0; k < 4; ++k) {
int nr = r + dr[k];
int nc = c + dc[k];
int nv = 0;
if (0 <= nr && nr < N && 0 <= nc && nc < N) {
nv = grid[nr][nc];
}
ans += max(grid[r][c] - nv, 0);
}
}
}
}
return ans;
}
};
5、检查二进制字符串字段
给你一个二进制字符串 s ,该字符串 不含前导零 。
如果 s 包含 零个或一个由连续的 '1' 组成的字段 ,返回 true 。否则,返回 false 。
示例 1:
输入:s = "1001"
输出:false
解释:字符串中的 1 没有形成一个连续字段。
示例 2:
输入:s = "110"
输出:true
解答:
class Solution:
def checkOnesSegment(self, s: str) -> bool:
n=len(s)
for i in range(n-1):
if(s[i]=='0' and s[i+1]=='1'):
return False
return True
参考答案:
class Solution:
def checkOnesSegment(self, s: str) -> bool:
return '01' not in s