LeetCode Weekly Contest 56 解题报告

LeetCode Weekly Contest 56 解题报告

对应 No.717,718,719443 的题解。

如前面几篇博客中说的那样, 我想换些形式来写这东西。(毕竟有一定的任务性质, 还是有点枯燥的) 这种以Contest的形式早就想过了, 只不过之前Contest的题没有完整做出过 Orz….. 总算这次的题略水一点。就先做一次合集吧。

T717 以及 T443

由于这两题都是easy, 所以放一起作为一个板块写。

T717 题目描述:

We have two special characters. The first character can be represented by one bit 0. The second character can be represented by two bits (10 or 11).

Now given a string represented by several bits. Return whether the last character must be a one-bit character or not. The given string will always end with a zero.

Note:
1 <= len(bits) <= 1000.
bits[i] is always 0 or 1.

这个编码是一个长度为2的哈夫曼编码。所以可以从头开始直接匹配, 不存在有多种匹配的可能性。
所以很容易得到时间复杂度为 O(n) 的算法:依次扫描,如果是0,则匹配为 0, 如果是1,则一次匹配两个字符。

AC代码如下:

class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        int i = 0;
        bool isOne;
        while (i < bits.size()) {
            if (bits[i] == 1) {
                isOne = false;
                i+= 2;
            }
            else {
                isOne = true;
                i++;
            }
        }
        return isOne;
    }
};

T443 题目描述:

Given an array of characters, compress it in-place.

The length after compression must always be smaller than or equal to the original array.

Every element of the array should be a character (not int) of length 1.

After you are done modifying the input array in-place, return the new length of the array.

题目还附了许多样例, 建议直接去看一遍题:https://leetcode.com/problems/string-compression/description/

题目大意就是说把一个字符串进行压缩, 压缩的主体是连续出现的字符。 把连续出现的字符用字符和出现的次数来表示。

这题是一道基础题吧。 就是简单的编程实现功能即可。 并不需要什么算法。需要注意的是:
1. 出现的次数可能是多位数, 不局限于个位数, 因此需要实现一个itoa()函数。
2. 最后一次要注意判断压缩以及进行压缩。

AC代码如下:

class Solution {
public:
    string itoa(int n) {
        if (n == 0) return "0";
        string ans = "";
        while (n != 0) {
            ans.insert(ans.begin(), '0' + n % 10);
            n/= 10;
        }
        return ans;
    }
    void Compress(vector<char> &chars, int &j, char x, int nums) {
        string times = itoa(nums);
        chars[j] = x; ++j;
        for (int i = 0; i < times.size(); ++i) {
            chars[j] = times[i];
            ++j;
        }
    }
    int compress(vector<char>& chars) {
        int count = 1, j = 0;
        for (int i = 1; i < chars.size(); ++i) {
            while (i < chars.size() && chars[i] == chars[i - 1]) {
                count++;
                i++;
            }
            if (i >= chars.size()) break;
            if (count > 1) { 
                Compress(chars, j, chars[i - 1], count);
            }
            else {
                chars[j] = chars[i - 1];
                j++;
            }
            count = 1;
        }
        if (count > 1) { 
            Compress(chars, j, chars[chars.size() - 1], count);
        }
        else {
            chars[j] = chars[chars.size() - 1];
            j++;
        }
        return j;
    }
};

T718

Given two integer arrays A and B, return the maximum length of an subarray that appears in both arrays.
Example 1:
Input:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
Output: 3
Explanation:
The repeated subarray with maximum length is [3, 2, 1].

Note:
1. 1 <= len(A), len(B) <= 1000
2. 0 <= A[i], B[i] < 100

题目大意

这道题是找出两个串的最长公共子串。从题目描述也能看出, 这题和著名的DP LCS 十分相似。事实上分析下来, 就是用 LCS 的方法就可以解。状态转移方程如下:

Count[i][j] = A[i] == B[j] ? Conut[i - 1][j - 1] + 1 : 0

这是典型的DP。 思路就不多解释了。 如果不理解请先去了解 LCS 的解法。
这里需要注意到, 根据这个状态转移方程, 我们可以对状态进行压缩, 以节省空间复杂度。可以看到, 每一层的迭代只和其上一层有关。因此我们最多只需保留两层的状态, 反复迭代即可。 关键在于, 如果我们调整j的搜索顺序, 改为从后向前搜索, 那么可以完美的压缩一维, 即只用保留当前这一层的状态。

(剧透: 这题不状态压缩会 MLE , 不然我也懒得写。。。

以下是AC代码, 基本就是上面状态转移方程的代码实现, 重点是循环的顺序

class Solution {
public:
    int findLength(vector<int>& A, vector<int>& B) {
        vector<int> count(B.size(), 0);
        int maximum = 0;
        for (int i = 0; i < A.size(); ++i) {
            for (int j = B.size() - 1; j >= 0; --j) {
                if (A[i] != B[j]) {
                    count[j] = 0;
                }
                else {
                    if (i == 0 || j == 0) count[j] = 1;
                    else count[j] = count[j - 1] + 1;
                }
                if (count[j] > maximum) maximum = count[j];
            }
        }
        return maximum;
    }
};

T719

题目描述

Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pair (A, B) is defined as the absolute difference between A and B.
Input:
nums = [1,3,1]
k = 1
Output: 0
Explanation:
Here are all the pairs:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
Then the 1st smallest distance pair is (1,1), and its distance is 0.

Note:
1. 2 <= len(nums) <= 10000.
2. 0 <= nums[i] < 1000000.
3. 1 <= k <= len(nums) * (len(nums) - 1) / 2.

题目分析

emmm,这题的数据范围我觉得比较有意思。 由于是[1,10000],一般而言, 用 O(n2) 的方式对于这种数据量是勉强够的。 但是可能会受到具体实现的时候写法的制约。(就是有可能一个小优化没有考虑到就会超时的那种)

再来看题意。 首先这种数对的数量是 O(n2) 数量级的。也就是光完全构造就要 O(N2) . emm考虑到我暂时没想到如何不完全构造就能实现,所以我打算先用 O(n2) 的方式实现下试试看。

既然用了 O(n2) , 就必须在其他地方尽量节约时间。 事实上除了构造部分, 就是挑选第 k 大的数。显然直接去排序 不是一个明智的选择(排序的复杂度是 n2log(n) ,这想要过是很困难的)。这时候 note的作用就很明显了:其中1,3是常规的规定数据范围。 用于控制复杂度。 而2条件是开始没有被用到的。而且这种无端给整数范围的条件一般也就一种可能: 桶排序。
桶的范围是[1, 1000000], 小于复杂度 O(n2) . 因此总复杂度还是 O(n2)

(交上去是过了,不过耗时肯定在正态分布之外。。)

以下是AC代码。 整个代码非常短, 只有10来行。 完全看不出这是一道Hard

class Solution {
public:
    int smallestDistancePair(vector<int>& nums, int k) {
        vector<int> count(1000000, 0);
        for (int i = 0; i < nums.size() - 1; ++i) {
            for (int j = i + 1; j < nums.size(); ++j) {
                count[abs(nums[i] - nums[j])]++;
            }
        }
        int sum = 0;
        for(int i = 0; i < 10000000; ++i) {
            sum+= count[i];
            if (sum >= k) return i;
        }
    }
};

Contest 总结

这次的Contest我觉得是我做过的最简单的一次。题目分布是 2Easy, 1Medium, 1Hard. 容易在于, Hard的数据量卡的不严, 一个比较trival的解法也能蹭过;而Medium是一个朴素DP, 只是考察了一个状态压缩。从时间上来说, 我觉得每道题的分配时间理想情况下应大概为: 10min, 15min, 15min, 10min 中间两题时间略多是因为一个是要对字符串进行处理, 稍不留神可能会错; 另一个是考虑到要推出状态转移, 并且要进行状态压缩。

当然实际做的时候哪有那么理想。。。我觉得大概90min做完就差不多吧。

(残念: 这次因为睡晚了只在Contest最后半小时开始, 到最后只A了前两题Orz。。。)

The End.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: for i in range(len(nums)): for j in range(i+1, len(nums)): if nums[i] + nums[j] == target: return [i, j] ### 回答2: leetcode 第1题是"两数之和",题目要求在给定的整数数组中找到两个数,使它们的和等于一个目标值,并返回这两个数的索引。下面是使用哈希表解决这个问题的Python代码: ```python def twoSum(nums, target): # 创建一个空的哈希表 hashmap = {} # 遍历整个数组 for i, num in enumerate(nums): # 计算当前数字与目标值的差值 complement = target - num # 如果差值存在于哈希表中,则返回差值的索引和当前数字的索引 if complement in hashmap: return [hashmap[complement], i] # 将当前数字添加到哈希表中,索引作为键,数字作为值 hashmap[num] = i # 如果未找到符合条件的数字,则返回空列表 return [] ``` 这个算法的基本思想是,在遍历整个数组的过程中,先计算当前数字与目标值的差值,然后将差值与当前数字的索引存储在哈希表中。接下来,在遍历数组的过程中,如果差值存在于哈希表中,则说明找到了两个数的和等于目标值,直接返回这两个数的索引。如果遍历完成后仍未找到符合条件的数对,则返回空列表。这个算法的时间复杂度为 O(n),其中 n 为数组的长度。 ### 回答3: 题目描述:两数之和 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。 示例: 输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。 思路:使用字典存储数组中的数字及其对应的下标,然后遍历数组找到与目标值的差值,如果差值也在字典中,说明找到了答案。 具体实现如下: ```python def twoSum(nums, target): # 创建一个字典存储数组中的数字及其对应的下标 num_dict = {} for i in range(len(nums)): # 计算与目标值的差值 complement = target - nums[i] # 如果差值也在字典中,说明找到了答案 if complement in num_dict: return [num_dict[complement], i] # 将数字及其对应的下标存入字典中 num_dict[nums[i]] = i return [] nums = [2, 7, 11, 15] target = 9 result = twoSum(nums, target) print(result) # 输出 [0, 1] ``` 以上就是 LeetCode 第1题的 Python 解题代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值