序号561
题目:给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。
解析:使用排序,从小到大把间隔 2 的都加起来
这次使用qsort
int cmp (const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
int arrayPairSum(int* nums, int numsSize){
int sum = 0;
qsort(nums, numsSize, sizeof(int), cmp);
for (int i = 0; i < numsSize; i += 2)
{
sum += nums[i];
}
return sum;
}
序号566
题目:给出一个由二维数组表示的矩阵,以及两个正整数r和c,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的行遍历顺序填充。
如果具有给定参数的reshape操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
解析:
- 理解参数
numsSize是行数,returnSize也是行数 - 理解二维数组
二维数组本质是一维数组,所以用位置标记位置
cnt / c 是行位置,cnt % c 是列位置
int** matrixReshape(int** nums, int numsSize, int* numsColSize, int r, int c, int* returnSize, int** returnColumnSizes){
int m = numsSize;
int n = numsColSize[0];
if (m * n != r * c)
{
*returnSize = m;
*returnColumnSizes = (int*)malloc(sizeof(int) * m);
for (int i = 0; i < m; i++)
(*returnColumnSizes)[i] = n;
return nums;
}
else
{
int** ans = (int**)malloc(sizeof(int*) * r);
*returnColumnSizes = (int*)malloc(sizeof(int) * r);
int cnt = 0;
for (int i = 0; i < r; i++)
ans[i] = (int*)malloc(sizeof(int) * c);
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
ans[cnt / c][cnt % c] = nums[i][j];
cnt++;
}
}
*returnSize = r;
for (int i = 0; i < r; i++)
(*returnColumnSizes)[i] = c;
return ans;
}
}
序号581
题目:给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
你找到的子数组应是最短的,请输出它的长度。
解析:
- 排序
复制数组排序,比较原数组和有序的不匹配边界
时间 O ( n l o g n ) O(nlogn) O(nlogn),空间 O ( n ) O(n) O(n) - 模拟
要确定边界,可以先找无序子数组中的最小值和最大值
再找到第一个大于最小值,最后一个小于最大值,便是边界
时间 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)
这里采用第二种
int findUnsortedSubarray(int* nums, int numsSize){
int min = INT_MAX;
int max = INT_MIN;
int flag = 0;
for (int i = 1; i < numsSize; i++) //子数组内最小值
{
if (!flag && nums[i] < nums[i-1])
flag = 1;
if (flag && nums[i] < min)
min = nums[i];
}
flag = 0;
for (int i = numsSize - 2; i >= 0; i--) //子数组内最大值
{
if (!flag && nums[i] > nums[i+1])
flag = 1;
if (flag && nums[i] > max)
max = nums[i];
}
int left, right; //左右边界
for (left = 0; left < numsSize; left++)
{
if (nums[left] > min)
break;
}
for (right = numsSize - 1; right >= 0; right--)
{
if (nums[right] < max)
break;
}
return right - left < 0 ? 0 : right - left + 1;
}
序号605
题目:假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花),和一个数 n 。能否在不打破种植规则的情况下种入 n 朵花?能则返回True,不能则返回False。
解析:模拟
- 第1、2位置为0,可以
- 倒数1、2位置为0,可以
- 中间要自己、两边都为0,可以
这个逻辑判断很巧妙,利用短路性质
bool canPlaceFlowers(int* flowerbed, int flowerbedSize, int n) {
int cnt = 0;
for (int i = 0; i < flowerbedSize; i++)
{
if (flowerbed[i] == 0 && (i == 0 || flowerbed[i-1] == 0)
&& (i == flowerbedSize - 1 || flowerbed[i+1] == 0))
{
cnt++;
flowerbed[i] = 1;
}
}
return cnt >= n ? true : false;
}
注:源自于题解
序号628
题目:给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
解析:
- 找前三大的数
- 找最大的,和前二小
也可以直接排序
int maximumProduct(int* nums, int numsSize){
int min1 = INT_MAX, min2 = INT_MAX;
int max1 = INT_MIN, max2 = INT_MIN, max3 = INT_MIN;
int cur;
for (int i = 0; i < numsSize; i++)
{
cur = nums[i];
if (cur < min1)
{
min2 = min1;
min1 = cur;
}
else if (cur < min2)
min2 = cur;
if (cur > max1)
{
max3 = max2;
max2 = max1;
max1 = cur;
}
else if (cur > max2)
{
max3 = max2;
max2 = cur;
}
else if (cur > max3)
max3 = cur;
}
int num1 = max1*max2*max3;
int num2 = max1*min1*min2;
return num1 > num2 ? num1 : num2;
}
序号643
题目:给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数。
解析:定长的子数组
- 滑动窗口法
计算窗口的平均值,更新最大,移动窗口
double findMaxAverage(int* nums, int numsSize, int k){
int windowStart = 0;
double windowSum = 0;
double ans = -10000;
double average;
for (int windowEnd = 0; windowEnd < numsSize; windowEnd++)
{
windowSum += nums[windowEnd];
if (windowEnd + 1 >= k)
{
average = windowSum / k;
if (average > ans)
ans = average;
windowSum -= nums[windowStart];
windowStart++;
}
}
return ans;
}
序号661
题目:包含整数的二维矩阵 M 表示一个图片的灰度。你需要设计一个平滑器来让每一个单元的灰度成为平均灰度 (向下舍入) ,平均灰度的计算是周围的8个单元和它本身的值求平均,如果周围的单元格不足八个,则尽可能多的利用它们。
解析:模拟,对每个位置,周围不越界的相加,同时累计邻居数
int** imageSmoother(int** M, int MSize, int* MColSize, int* returnSize, int** returnColumnSizes){
int** ans = (int**)malloc(sizeof(int*) * MSize);
for (int i = 0; i < MSize; i++)
ans[i] = (int*)malloc(sizeof(int) * MColSize[i]);
int cnt, sum;
for (int r = 0; r < MSize; r++)
{
for (int c = 0; c < MColSize[0]; c++)
{
cnt = 0;
sum = 0;
for (int nR = r-1; nR <= r+1; nR++)
{
for (int nC = c-1; nC <= c+1; nC++)
{
if (0 <= nR && nR < MSize && 0 <= nC && nC < MColSize[0])
{
cnt++;
sum += M[nR][nC];
}
}
}
ans[r][c] = sum / cnt;
}
}
*returnSize = MSize;
*returnColumnSizes = (int*)malloc(sizeof(int) * MSize);
for (int i = 0; i < MSize; i++)
(*returnColumnSizes)[i] = MColSize[0];
return ans;
}
序号665
题目:给定一个长度为 n 的整数数组,你的任务是判断在最多改变 1 个元素的情况下,该数组能否变成一个非递减数列。
我们是这样定义一个非递减数列的: 对于数组中所有的 i (1 <= i < n),满足 array[i] <= array[i + 1]。
解析:模拟处理,逆序的两个,改变其中之一
- 先变当前位置,
nums[i] = nums[i-1
,满足非递减 - 再判断是否可以递增,否则改变后者
nums[i+1] = nums[i]
bool checkPossibility(int* nums, int numsSize){
int cnt = 0;
for (int i = 0; i < numsSize-1; i++)
{
if (nums[i] <= nums[i+1])
continue;
else
cnt++;
int temp = nums[i];
if (i > 0)
nums[i] = nums[i-1];
else
nums[i] = nums[i+1];
if (nums[i] > nums[i+1])
{
nums[i] = temp;
nums[i+1] = temp;
}
}
return cnt > 1 ? false : true;
}
序号674
题目:给定一个未经排序的整数数组,找到最长且连续的的递增序列。
解析:连续,可考虑动态规划
- 因为只考虑一个位置,可以只用一个变量
nums[i] > nums[i-1]
len++,否则置于1
int findLengthOfLCIS(int* nums, int numsSize){
if (numsSize < 2)
return numsSize;
int len = 1;
int ans = 1;
for (int i = 1; i < numsSize; i++)
{
if (nums[i] > nums[i-1])
{
len++;
if (len > ans)
ans = len;
}
else
len = 1;
}
return ans;
}
序号697
题目:给定一个非空且只包含非负数的整数数组 nums, 数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
解析:
- 统计频数
由于数组不能动,一是用 hash,二是复制数组再排序 - 子数组长度
由于可能存在多个最大频数的数,用 left、right 记录他们的边界
left、right 记录的是位置,把 0 留出来
int findShortestSubArray(int* nums, int numsSize){
int max = nums[0];
for (int i = 1; i < numsSize; i++)
max = nums[i] > max ? nums[i] : max;
int* hash = (int*)calloc(max+1, sizeof(int));
int* left = (int*)calloc(max+1, sizeof(int));
int* right = (int*)calloc(max+1, sizeof(int));
int most = 0, temp;
for(int i = 0; i < numsSize; i++)
{
temp = nums[i];
hash[temp]++;
if (hash[temp] > most)
most = hash[temp];
}
for (int i = 0; i < numsSize; i++)
{
temp = nums[i];
if (hash[temp] == most)
{
if (left[temp] == 0) //left只在这里改变
{
left[temp] = i + 1;
right[temp] = i + 1;
}
else
right[temp] = i + 1;
}
}
int ans = 50001, len;
for (int i = 0; i <= max; i++)
{
if(left[i] != 0)
{
len = right[i] - left[i] + 1;
if (len < ans)
ans = len;
}
}
free(hash);
free(left);
free(right);
return ans;
}
序号717
题目:有两种特殊字符。第一种字符可以用一比特0来表示。第二种字符可以用两比特(10 或 11)来表示。
现给一个由若干比特组成的字符串。问最后一个字符是否必定为一个一比特字符。给定的字符串总是由0结束。
解析:模拟,bits[i] 为 1,pos 加 2。如果有最后一个字符,就判断
bool isOneBitCharacter(int* bits, int bitsSize){
int pos = 0;
while (pos < bitsSize)
{
if (pos == bitsSize - 1 && bits[pos] == 0)
return true;
if (bits[pos] == 1)
pos += 2;
else
pos++;
}
return false;
}
序号724
题目:给定一个整数类型的数组 nums,请编写一个能够返回数组“中心索引”的方法。
我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。
如果数组不存在中心索引,那么我们应该返回 -1。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。
解析:元素相加,可以想到累加
- 做一个累加数组,右侧的和为
arr[numsSize - 1] - arr[i]
特判 0 和 numsSize - 1的位置
int pivotIndex(int* nums, int numsSize){
if (numsSize < 2)
return numsSize-1;
int* arr = (int*)malloc(sizeof(int) * numsSize);
arr[0] = nums[0];
for (int i = 1; i < numsSize; i++)
arr[i] = arr[i-1] + nums[i];
if (arr[numsSize-1] - arr[0] == 0)
return 0;
for (int i = 1; i < numsSize - 1; i++)
{
if (arr[i-1] == arr[numsSize-1] - arr[i])
return i;
}
if (arr[numsSize-2] == 0)
return numsSize - 1;
free(arr);
return -1;
}
序号746
题目:数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 costi。
每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。
您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。
解析:
- 运用动态规划
离开当前位置的花费 = 前两梯最小花费 + 当前花费
dp[i] = cost[i] + Min(dp[i-1], dp[i-2])
由于只用到 2 个位置,所以用 2 个变量更替即可
int minCostClimbingStairs(int* cost, int costSize){
int* dp = (int*)malloc(sizeof(int) * 2);
int i, ans;
dp[0] = cost[0];
dp[1] = cost[1];
for (i = 2; i < costSize; i++)
{
ans = cost[i] + (dp[0] < dp[1] ? dp[0] : dp[1]);
dp[0] = dp[1];
dp[1] = ans;
}
ans = dp[0] < dp[1] ? dp[0] : dp[1];
free(dp);
return ans;
}
注:源自于题解
序号747
题目:在一个给定的数组nums中,总是存在一个最大元素 。
查找数组中的最大元素是否至少是数组中每个其他数字的两倍。
如果是,则返回最大元素的索引,否则返回-1。
解析:
- 模拟
先找到最大值,若比其他数字都大 2 倍,只需比第二大的数大 2 倍
int dominantIndex(int* nums, int numsSize){
int first = -1;
int second = -1;
int maxIndex = 0;
for (int i = 0; i < numsSize; i++)
{
if (nums[i] > first)
{
second = first;
first = nums[i];
maxIndex = i;
}
else if (nums[i] > second)
second = nums[i];
}
return first >= 2*second ? maxIndex : -1;
}
序号766
题目:如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵。
给定一个 M x N 的矩阵,当且仅当它是托普利茨矩阵时返回 True。
解析:
- 模拟
对角线上,比较matrix[r][c] == matrix[r-1][c-1]
bool isToeplitzMatrix(int** matrix, int matrixSize, int* matrixColSize){
for (int r = 0; r < matrixSize; r++)
{
for (int c = 0; c < matrixColSize[r]; c++)
{
if (r > 0 && c > 0 && matrix[r][c] != matrix[r-1][c-1])
return false;
}
}
return true;
}
序号830
题目:在一个由小写字母构成的字符串 S 中,包含由一些连续的相同字符所构成的分组。
例如,在字符串 S = “abbxxxxzyy” 中,就含有 “a”, “bb”, “xxxx”, “z” 和 “yy” 这样的一些分组。
我们称所有包含大于或等于三个连续字符的分组为较大分组。找到每一个较大分组的起始和终止位置。
最终结果按照字典顺序输出。
解析:
- 模拟
开辟空间为 len/3,遇到相等的前后字符,开始判断后面的字符是否符合条件
int** largeGroupPositions(char * S, int* returnSize, int** returnColumnSizes){
int len = strlen(S);
int** ans = (int**)malloc(sizeof(int*) * (len/3));
for (int i = 0; i < len/3; i++)
ans[i] = (int*)malloc(sizeof(int) * 2);
int cnt = 0, subLen;
int start, end;
for (int i = 1; i < len; i++) //这个地方用 len,不用 S[i] != '\0',因为内部也有移动,再加可能越界
{
if (S[i] == S[i-1])
{
start = i - 1;
subLen = 1;
for (;i < len && S[i] == S[i-1]; i++)
subLen++;
end = i;
if (end - start >= 3)
{
ans[cnt][0] = start;
ans[cnt][1] = end - 1;
cnt++;
}
}
}
*returnSize = cnt;
*returnColumnSizes = (int*)malloc(sizeof(int) * cnt);
for (int i = 0; i < cnt; i++)
(*returnColumnSizes)[i] = 2;
return ans;
}