目录
【题2】LeetCode1566:重复至少 K 次且长度为 M 的模式
4 模拟法
4.1 简介
枚举法是利用计算机运算速度快、精确度高的特点,对要解决问题的所有可能情况,一个不漏地进行检验,从中找出符合要求的答案,因此枚举法是通过牺牲时间来换取答案的全面性。在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。
4.2 特点
将问题的所有可能的答案一一列举,然后根据条件判断此答案是否合适,合适就保留,不合适就丢弃。例如:找出1到100之间的素数,需要将1到100之间的所有整数进行判断。枚举算法因为要列举问题的所有可能的答案,所以它具备以下几个特点:
- 得到的结果肯定是正确的;
- 可能做了很多的无用功,浪费了宝贵的时间,效率低下;
- 通常会涉及到求极值(如最大,最小,最重等);
- 数据量大的话,可能会造成时间崩溃。
4.3 基本思路
枚举法的基本思想是: 逐一列举问题所涉及的所有情形,并根据问题提出的条件检验哪些是问题的解,哪些应予排除。 采用枚举算法解题的基本思路:
- 确定枚举对象、枚举范围和判定条件;
- 枚举可能的解,验证是否是问题的解。
结构:枚举算法的一般结构:循环+判断语句。
4.4 优缺点
优点:算法简单,正确性容易证明,在局部地方使用枚举法,效果十分的好。
缺点:运算量过大,当问题的规模变大的时候,循环的阶数越大,执行速度越慢,可能超时。
4.5 枚举法的优化
枚举法的时间复杂度可以用状态总数*考察单个状态的耗时来表示,因此优化主要是:
- 减少状态总数(即减少枚举变量和枚举变量的值域)
- 降低单个状态的考察代价。
优化过程从几个方面考虑。具体讲
- 提取有效信息;
- 减少重复计算;
- 将原问题化为更小的问题;
- 根据问题的性质进行截枝;
4.6 题典
【题1】Leetcode1534:统计好三元组
数组 arr
,以及 a
、b
、c
三个整数。请你统计其中好三元组的数量。如果三元组 (arr[i], arr[j], arr[k])
满足下列全部条件,则认为它是一个 好三元组 。
0 <= i < j < k < arr.length
|arr[i] - arr[j]| <= a
|arr[j] - arr[k]| <= b
|arr[i] - arr[k]| <= c
其中 |x|
表示 x
的绝对值。返回 好三元组的数量 。
示例 1:
输入:arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3
输出:4
解释:一共有 4 个好三元组:[(3,0,1), (3,0,1), (3,1,1), (0,1,1)] 。
示例 2:
输入:arr = [1,1,2,2,3], a = 0, b = 0, c = 1
输出:0
解释:不存在满足所有条件的三元组。
题解:
class Solution {
public:
int countGoodTriplets(vector<int>& arr, int a, int b, int c) {
int n = arr.size(), cnt = 0;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
for (int k = j + 1; k < n; ++k) {
if (abs(arr[i] - arr[j]) <= a && abs(arr[j] - arr[k]) <= b && abs(arr[i] - arr[k]) <= c) {
++cnt;
}
}
}
}
return cnt;
}
};
【题2】LeetCode1566:重复至少 K 次且长度为 M 的模式
给你一个正整数数组 arr
,请你找出一个长度为 m
且在数组中至少重复 k
次的模式。模式 是由一个或多个值组成的子数组(连续的子序列),连续 重复多次但 不重叠 。 模式由其长度和重复次数定义。如果数组中存在至少重复 k
次且长度为 m
的模式,则返回 true
,否则返回 false
。
示例 1:
输入:arr = [1,2,4,4,4,4], m = 1, k = 3
输出:true
解释:模式 (4) 的长度为 1 ,且连续重复 4 次。注意,模式可以重复 k 次或更多次,但不能少于 k 次。
示例 2:
输入:arr = [1,2,1,2,1,1,1,3], m = 2, k = 2
输出:true
解释:模式 (1,2) 长度为 2 ,且连续重复 2 次。另一个符合题意的模式是 (2,1) ,同样重复 2 次。
题解:
class Solution {
public:
bool containsPattern(vector<int>& arr, int m, int k) {
int n = arr.size();
for (int l = 0; l <= n - m * k; ++l) {
int offset;
for (offset = 0; offset < m * k; ++offset) {
if (arr[l + offset] != arr[l + offset % m]) {
break;
}
}
if (offset == m * k) {
return true;
}
}
return false;
}
};