LeetCode第一天(实际第二天)

写在前面:题目来源于剑指offer,有些题解也是offer中的,所以想看的更加详细,请直接在LeetCode上搜索

问题一:单词长度的最大乘积

题目:给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。

题目拆解:

1)找到两个不包含相同字符的字符串

2)计算字符串长度的乘积

初始思路:

四层for循环,遍历所有结果

        int ans = 0;

        for(int i =0;i<words.size() - 1;++i)

        {

            for (int j = i + 1; j < words.size(); ++j)

            {

                bool sign = true;

                //判断 两个字符是否存在相等字母

                int w1 = words[i].size(), w2 = words[j].size();

                int nsize = min(w1, w2);

                for (int k = 0; k < w1; ++k)

                {

                    for(int m = 0; m < w2; ++m)

                    {

                        if (words[i][k] == words[j][m])

                        {

                            sign = false;

                            break;

                        }

                    }

                    if(!sign)

                    {

                        break;

                    }

                }

                int temp = w1 * w2;

                if (sign && ans < temp)

                    ans = temp;

            }

        }

        return ans;

测试结果:超出时间限制。

优化思路:

1)减少比较时间。测试用例中,超出时间的原因是,每个字符串都是相同字符,而且特别长。同时从题目中也可以发现,字符串的输入范围是26个小写字母,可以借助位运算简化比较过程。

示例“abc” = 0000...0111;“abbc” = 0000...0111;

一开始想半天不知道如何用位运算表达,看了题解才发现如此简单,学无止境。

       int sumlen = words.size();

        int i =0,j=0;

        vector<int> maskdata(sumlen,0);

        for(i = 0; i<sumlen;++i)

        {

            for(j = 0; j<words[i].size(); ++j)

            {

                maskdata[i] |= (1<<(words[i][j] - 'a'));

            }

        }

        int ans = 0;

        for(i =0;i<words.size() - 1;++i)

        {

            for (j = i + 1; j < words.size(); ++j)

            {

                int w1 = words[i].size(), w2 = words[j].size();

                int temp = w1 * w2;

                // 比当前答案大才有计算的必要

                if(temp < ans)

                    continue;

                // 判断是否存在相同字符

                if(maskdata[i] & maskdata[j])

                    continue;

                // 更新答案

                ans = temp;

            }

        }

        return ans;

上述代码是看过题解之后自己编写的,算是一点点自己的东西,哈哈,又是无效学习的一天。

此时我已经想不到优化的方向了,所以继续看题解:

题解中的优化是考虑到了mask重复的问题,进行减少计算,但是大方向并没有改变,因此并不是另一种思路。

启示:位运算也可以做去重复的操作。

题目二:排序数组中两个数字之和

给定一个已按照 升序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target

解题思路:

问题定性为查找问题,而且已知数组为升序数组,所以目标应该进一步细化为减少搜索任务上,因此,我的第一个思路为遍历数组,有序从数组中取值与target作差,在数组中通过二分法查找差值。

        int first = 0;

        int nsize = numbers.size();

        for(first = 0; first < nsize; ++first)

        {

            int ohalf = target - numbers[first];

            int bl = first +1;

            int br = nsize - 1;

            while(bl<=br)

            {

                int mid = bl + ( (br - bl) >> 1);

                if(numbers[mid] == ohalf)

                    return {first, mid};

                else if(numbers[mid] > ohalf)

                    br = mid - 1;

                else

                    bl = mid + 1;

            }

        }

        return {0};

编写过程中自己的问题是,二分查找的判断条件,左边边界是小于等于还是小于,如果是小于,则跳出while循环时还需要讨论左边是否等于右边界的情况。

还有一个思维误区是判断是否加1的问题,在选择小于的情况下,如何解决3和4反复横跳的问题。一直陷在思维误区,因此以后遇到二分查找问题,只需要考虑数据即可

查找模式

int bl = 查找起始位置

int br = 查找结束位置

while(bl <= br)

{

        int mid = bl + ( (br - bl) >> 1);

        if(等于中间值)

        else if(大于中间值)

                mid + 1

        else 小于中间值

                mid - 1

}

现在做题做的比较少,先这样考虑,遇到新问题再回来修改(2022.8.1)

昨天临走,又发现双指针方法也适合有序数组的查找

        int bl = 0;

        int br = numbers.size() - 1;

        while(bl < br)

        {

            if(numbers[bl] + numbers[br] == target)

                return {bl,br};

            else if(numbers[bl]+numbers[br]>target)

                br -=1;

            else

                bl +=1;

        }

        return {0};

总结:

二分查找、双指针、位运算去重

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值