leetcode题解-2020.03.29(题目编号1/892/914/999/820/1162/2/3)

本文是作者一周内在LeetCode上完成的编程题目的总结,包括1、892、914、999、820、1162、2、3号题目。每个题目包括题目描述、解题思路和示例代码,涵盖了数组、二维空间、数学逻辑等多个方面,适合程序员刷题参考。
摘要由CSDN通过智能技术生成

前言

本周完成的题目有:

  • 1 两数之和(简单难度)
  • 892 三维形体的表面积(简单难度,每日一题)
  • 914 卡牌分组(简单难度,每日一题)
  • 999 可以被一步捕获的棋子数(简单难度,每日一题)
  • 820 单词的压缩编码(中等难度,每日一题)
  • 1162 地图分析(中等难度,每日一题)
  • 2 两数相加(中等难度)
  • 3 无重复字符的最长子串(中等难度)

博客专栏地址:https://blog.csdn.net/feng964497595/category_9848847.html
github地址:https://github.com/mufeng964497595/leetcode

1 两数之和

题目描述

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

思路解析

  1. 一般题目拿到手,先考虑最简单的暴力算法。题目要找数,而且只找两个,那就很简单地用两个for循环嵌套遍历一波,把两两组合都算出来就可以了,注意别重复取同一个数了,例如输入[1,2,3],要找4,就不能返回[1, 1],而要返回[0, 2]。
  2. 暴力算法之外,有没有更快一点的?当然有啦。题目输入是一个数组,要我们输出下标,那一般就是要把数值的值和下标记录起来。所以,我们可以用一个map来记录值与下标的关系,把数组的值和下标都放到map里,然后遍历map,看目标值-当前遍历到的值是不是也在map中,且与当前遍历到的值不在同一个位置,如果是的话,那就找到结果了。
  3. 方法2有没有问题?当然有=_=||。考虑这样一组用例:[1,3,3,2],目标值是6,那么在预处理的时候,map对于key相同的值会用后插入的结果来覆盖掉,所以map里面其实只有一个3,那么就会error啦。那可能会想到,使用multimap是不是能解决?答案是可以的,不过代码写起来会有点恶心,因为multimap查找key只会返回找到的其中一个值,没办法把所有key相同的结果都返回回来,要自己去搜,这性能就有点影响了。
  4. 那要怎么解决呢?其实很好办。我们前面是先预处理数组里的值到map中,才会有这个冲突的问题,那如果我们不预处理,而是先把map置为空,然后遍历数组,看目标值-当前遍历到的值是否在map中,如果不在,就插入map,在的话,那就是找到结果了,而且也不存在找到的两个值是同一个下标的情况。这样就解决上面的冲突问题啦。
  5. 可能有同学会问,对于key相同的情况,在map上不是依旧会冲突吗?其实不然。按题目的描述,一次只会有一个答案,那么对于key相同且其中一个下标是答案的一部分的情况,就只会是key相同的两个下标都是答案,且只会有两个key相同的下标,否则就跟题目的描述冲突了。既然只会有这种情况,而我是边遍历数组边插入map,那么就不存在这两个key都在map中这种情况了。

示例代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 用map来记录已搜索过的值&对应的下标
        std::map<int, int> mVal2Idx;
        vector<int> vRes;
        // 提前分配空间,避免push_back触发空间重新分配,影响性能
        vRes.reserve(2);
        int size = nums.size();
        for (int i= 0; i < size; ++i) {
            int val = target - nums[i];
            auto mit = mVal2Idx.find(val);
            if (mVal2Idx.end() == mit) {
                // 没找到,将数组当前值送入map
                mVal2Idx.insert(std::make_pair(nums[i], i));
            } else {
                // 从map中找到另一个值,那就得到结果了。
                // 对于数组中有两个值相同的情况也兼容了,
                // 因为题目说只有一个答案,那么如果出现两个值相同且其中一个是答案的情况,
                // 就只能是这两个值都是答案这一种可能。
                // 而此时map里只有一个值,所以不存在下标被覆盖的情况
                // mit->second比较小,放前面
                vRes.push_back(mit->second);
                vRes.push_back(i);
                break;
            }
        }

        return vRes;
    }
};

892 三维形体的表面积

题目描述

在 N * N 的网格上,我们放置一些 1 * 1 * 1 的立方体。
每个值 v = grid[i][j] 表示 v 个正方体叠放在对应单元格 (i, j) 上。
请你返回最终形体的表面积。

思路解析

  1. 算表面积,暴力算法就不太能搞了,要换换思路当成是智力题
  2. 假设,只有一列111的正方体,共n个,那么表面积怎么算呢?发挥下想象力,n个正方体竖着叠在一起,那么有四个侧面,每个侧面有n个11的面,那么侧面表面积就有4n,再加上上下两个面,所以表面积是4*n+2。(这里说的n>0哈)
  3. 如果每列正方体都没叠在一起,共m列,那么总的表面积也就可以算了,把每一列都套入公式算一下就好了。
  4. 但是题目这样出了,就肯定有一些叠在一起的,那么我们就用总的表面积来减去叠在一起的表面积就好了。那要怎么算那些叠在一起的呢?
  5. 单独看一列正方体,它被别人挡住的情况就只会出现在上下左右这四个方向,每个方向挡掉的表面积就是看谁矮了。例如一列有4个正方体,另一列有3个,两列并排放,那对于我这一列,就是挡掉3个嘛。
  6. 那么思路就清晰了:遍历网格的每一列,计算4*grid[i][j]+2得到这一列没被挡的总表面积(grid[i][j]=0就不用算了,直接跳过)。然后在分别比较一下grid[i][j]与它相邻的四个方向,减去小的那个高度,就得到当前列最终的表面积了。每一列都这样算就ok了。
  7. 是不是可以再优化一下呢?想想看哈,例如我们从i=0~n-1,j=0-n-1来遍历每一个网格,在访问它的四个方向的时候,对于当前列的左、下两个方向要减去的表面积,其实已经在计算左边这一列和下面这一列的时候就计算出来了,没必要再计算一次(两列并在一起,他们互相挡掉的表面积是一样的),在减去的时候*2就可以不用再浪费时间去再算一次左、下两个方向了。这可省掉了一半的时间。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值