【解题报告】《算法零基础100讲》(第31讲) 多维枚举(一) - 入门

前言

原文链接:《算法零基础100讲》(第31讲) 多维枚举(一) - 入门

在这里插入图片描述

概念

之前讲到的线性枚举,就是循环一遍来计数解决问题。那多维枚举就需要多重循环来解决问题。

int i, j, k;
for(i = 0; i < x; ++i) {
    for(j = 0; j < y; ++j) {
    	for(k = 0; k < z; ++k) {
        	....
        }
    }
}

392. 判断子序列

原题链接:392. 判断子序列

在这里插入图片描述

代码

循环一遍,当 *s与 *t 都没走到末尾时,如果当前位置字符相同,就让t往后走。

循环退出时,*s为 ‘\0’,取反就为真。

bool isSubsequence(char * s, char * t)
{
    while (*s && *t)
    {
        if (*s == *t)
        {
            s++;
        }
        t++;
    }

    return !*s;
}

240. 搜索二维矩阵 II

原题链接:240. 搜索二维矩阵 II

在这里插入图片描述

在这里插入图片描述

分析

因为这个矩阵的行和列都是按升序排列的,所以可以从矩阵的右上角开始查找。

若当前位置等于target,就退出;
若当前位置 > target,因为升序排列, 就从当前列往前找;
若当前位置 < target, 由于升序排列, 就直接改变行数。

这样的做法,每次改变都是改变整个行和列,比枚举快很多。

代码

bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target)
{
    if (NULL == matrix)
        return false;

    int row = 0, col = *matrixColSize - 1;

    while (row < matrixSize && col >= 0)
    {
        if (matrix[row][col] == target)
            return true;
        
        if (matrix[row][col] > target)
        {
            --col;
        }
        else
        {
            ++row;
        }
    }
    return false;   
}

2006. 差的绝对值为 K 的数对数目

原题链接 : 2006. 差的绝对值为 K 的数对数目

在这里插入图片描述

代码

直接按照题目要求枚举

int countKDifference(int* nums, int numsSize, int k)
{
    int count = 0;

    for (int i = 0; i < numsSize - 1; ++i)
    {
        for (int j = i + 1; j < numsSize; ++j)
        {
            if (nums[i] - nums[j] == k || nums[j] - nums[i] == k)
            {
                count++;
            }        
        }
    }
    return count;
}

389. 找不同

原题链接:389. 找不同

在这里插入图片描述

分析

我的做法是用一个数组,记录原字符串每个字母出现的次数,再遍历改变后的数组,对于每个出现的字符,在保存的数组中减去对应的字符个数;

如果某个字符个数被减到 -1,就说明找到这个字符了。

代码

char findTheDifference(char * s, char * t)
{
    if (NULL == s || NULL == t)
        return 0;
    
    int hash[26] = {0};

    for (int i = 0; i < strlen(s); ++i)
    {
        ++hash[s[i] - 'a'];
    }

    for (int i = 0; i < strlen(t); ++i)
    {
        --hash[t[i] - 'a'];

        if (hash[t[i] - 'a'] < 0)
            return t[i];
    }

    return '';
}

1431. 拥有最多糖果的孩子

原题链接:1431. 拥有最多糖果的孩子

在这里插入图片描述

代码

按照题目要求直接写出

很讨厌两种人:

  1. 写代码不写注释的人(没错好像是我)
  2. 让别人写注释的人。。。
bool* kidsWithCandies(int* candies, int candiesSize, int extraCandies, int* returnSize)
{
    *returnSize = 0;
    if (candies == NULL)
    return NULL;

    bool* ans = (bool*)malloc(sizeof(bool) * candiesSize);
    if (ans == NULL)
    return NULL;

    int i = 0;
    int max = -1;
    for (i; i < candiesSize; ++i)
    {
        if (max < candies[i])
        {
            max = candies[i];
        }
    }

    for (i = 0; i < candiesSize; ++i)
    {
        if (candies[i] + extraCandies >= max)
        {
            ans[i] = true;
        }
        else
        {
            ans[i] = false;
        }
    }

    *returnSize = candiesSize;
    return ans;
}

1588. 所有奇数长度子数组的和

原题链接: 1588. 所有奇数长度子数组的和

在这里插入图片描述

分析

如果多维枚举,时间复杂度为 O(n^3)

那如果利用前缀和, 可以将最内层循环时间复杂度优化为 O(1)。

代码

int sumOddLengthSubarrays(int* arr, int arrSize)
{
    if (NULL == arr)
        return 0;
    
    int prefixSums[arrSize + 1];
    memset(prefixSums, 0, sizeof(prefixSums));

    for (int i = 0; i < arrSize; i++)
    {
        prefixSums[i + 1] = prefixSums[i] + arr[i];
    }

    int sum = 0;

    for (int start = 0; start < arrSize; ++start)
    {
        for (int length = 1; start + length <= arrSize; length += 2)
        {
            int end = start + length - 1;

            sum += prefixSums[end + 1] - prefixSums[start];
        }
    }

    return sum;
}

1534. 统计好三元组

原题链接:1534. 统计好三元组

在这里插入图片描述

代码

直接根据题目多维枚举即可

int countGoodTriplets(int* arr, int arrSize, int a, int b, int c)
{
    if (NULL == arr)
        return 0;
    
    int count = 0;

    for (int i = 0; i < arrSize; ++i)
    {
        for (int j = i + 1; j < arrSize; ++j)
        {
            for (int k = j + 1; k < arrSize; ++k)
            {
                if (fabs(arr[i] - arr[j]) <= a && fabs(arr[j] - arr[k]) <= b && fabs(arr[i] - arr[k]) <= c)
                {
                    ++count;
                }
            }
        }
    }

    return count;
}

771. 宝石与石头

原题链接:771. 宝石与石头

在这里插入图片描述

代码

枚举

int numJewelsInStones(char * jewels, char * stones)
{
    if (jewels == NULL || stones == NULL)
        return 0;

    int jewelsLength = strlen(jewels);
    int stonesLength = strlen(stones);
    int count = 0;

    for (int i = 0; i < stonesLength; ++i)
    {
        for (int j = 0; j < jewelsLength; ++j)
        {
            if (stones[i] == jewels[j])
            {
                count++;
            }
        }
    }

    return count;
}

14. 最长公共前缀

原题链接:14. 最长公共前缀

在这里插入图片描述

分析

二维枚举,并在原字符串上改动,如果第一行的字符串的第 i 个字母与其他行哪个字母不同,就将 i 的位置改为字符串末尾, 即 ‘\0’。

代码

char * longestCommonPrefix(char ** strs, int strsSize)
{
    if (NULL == strs || strsSize == 0)
    return NULL;

    for (int i = 0; i < strlen(strs[0]); ++i)
    {
        char c = strs[0][i];
        for (int j = 0; j < strsSize; ++j)
        {
            if (c != strs[j][i])
            {
                strs[0][i] = '\0';
                return strs[0];
            }
        }
    }

    return strs[0];
}

1925. 统计平方和三元组的数目

原题链接:1925. 统计平方和三元组的数目

在这里插入图片描述

代码

多维枚举

int countTriples(int n)
{
    if(n == 1)
        return 0;

    int count = 0;
    for(int i = 1; i < n; i++)
    {
        for(int j = 1; j < n; j++)
        {
            for(int k = 1; k <= n; k++)
            {
                if(i * i + j * j == k * k)
                {
                    count++;
                }
            }
        }
    }
    return count;
}

练习题

1389. 按既定顺序创建目标数组

在这里插入图片描述

end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_索伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值