leetcode-数组-简单-C-第二部分

序号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操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。

解析

  1. 理解参数
    numsSize是行数,returnSize也是行数
  2. 理解二维数组
    二维数组本质是一维数组,所以用位置标记位置
    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

题目:给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
你找到的子数组应是最短的,请输出它的长度。

解析

  1. 排序
    复制数组排序,比较原数组和有序的不匹配边界
    时间 O ( n l o g n ) O(nlogn) O(nlogn),空间 O ( n ) O(n) O(n)
  2. 模拟
    要确定边界,可以先找无序子数组中的最小值和最大值
    再找到第一个大于最小值,最后一个小于最大值,便是边界
    时间 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. 第1、2位置为0,可以
  2. 倒数1、2位置为0,可以
  3. 中间要自己、两边都为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

题目:给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积。

解析

  1. 找前三大的数
  2. 找最大的,和前二小
    也可以直接排序
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 的连续子数组,并输出该最大平均数。

解析:定长的子数组

  1. 滑动窗口法
    计算窗口的平均值,更新最大,移动窗口
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]。

解析:模拟处理,逆序的两个,改变其中之一

  1. 先变当前位置,nums[i] = nums[i-1,满足非递减
  2. 再判断是否可以递增,否则改变后者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

题目:给定一个未经排序的整数数组,找到最长且连续的的递增序列。

解析:连续,可考虑动态规划

  1. 因为只考虑一个位置,可以只用一个变量
    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 拥有相同大小的度的最短连续子数组,返回其长度。

解析

  1. 统计频数
    由于数组不能动,一是用 hash,二是复制数组再排序
  2. 子数组长度
    由于可能存在多个最大频数的数,用 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。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。

解析:元素相加,可以想到累加

  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 的元素作为初始阶梯。

解析

  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。

解析

  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。

解析

  1. 模拟
    对角线上,比较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” 这样的一些分组。
我们称所有包含大于或等于三个连续字符的分组为较大分组。找到每一个较大分组的起始和终止位置。
最终结果按照字典顺序输出。

解析:

  1. 模拟
    开辟空间为 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值