做题回顾
在过去的两周,看了大概30道算法题,实际上自己动手编码完成的有10道左右,使用的语言为C++。相关题目如下:
还包含在王道书籍上面的几道题目,总体而言。题目的难度不是很大,看完题目之后都有思路,但是在细节方面总是掌握不好。经常就是能很快确认思路,但是一旦编码总是不能尽快通过,存在各种各样逻辑问题和编码问题。在做题的时候遇到的困难如下:
- 思路难以确定
- 思路存在问题,等到编码调试的时候才发现,比较让费时间
- 思路没有问题,但是将思路转化成具体的算法存在问题,在进行编码的时候在细节方面处理的不是很好
做题总结
确定算法思想
首先要知道常见的算法思想例如:蛮力法,贪心策略,动态规划,递归和分治,排序+查找,快排分区。
同时还要掌握常见的数据结构,从简单到复杂依次为:数组,链表,栈和队列,二叉树,平衡二叉树,(红黑树,B树,B+树了解计科),图论算法。其中最难的就是图论算法。后面需要花一点时间在图论上面。
什么时候使用蛮力法
在使用蛮力法之前一定要估算问题复杂度。下面是昨天晚上做的一道题目,可能存在更好的解法,但是也可以通过蛮力法进行解决。
Shortest Uncommon Substring in an Array - LeetCode Contest
题目大意:给定一个字符串数组arr,长度为n。现在需要生成一个字符串数组answers。且answers满足如下的条件:
answers[i]中保存的值是arr[i]的子串,且arr除arr[i]以外的其他字符串皆不包含该子串。若这样的子串有多个,则选择长度最短的子串;若他们长度相同,则按字典序排序,选择字典序最小的子串;如果没有这样的子串,则返回空。
算法限制
n == arr.length
2 <= n <= 100
1 <= arr[i].length <= 20
arr[i]
consists only of lowercase English letters.
下面包含两个例子:
Input: arr = ["cab","ad","bad","c"]
Output: ["ab","","ba",""]
Explanation: We have the following:
- For the string "cab", the shortest substring that does not occur in any other string is either "ca" or "ab", we choose the lexicographically smaller substring, which is "ab".
- For the string "ad", there is no substring that does not occur in any other string.
- For the string "bad", the shortest substring that does not occur in any other string is "ba".
- For the string "c", there is no substring that does not occur in any other string.
Example 2:
Input: arr = ["abc","bcd","abcd"]
Output: ["","","abcd"]
Explanation: We have the following:
- For the string "abc", there is no substring that does not occur in any other string.
- For the string "bcd", there is no substring that does not occur in any other string.
- For the string "abcd", the shortest substring that does not occur in any other string is "abcd".
思路分析:
在此之前,在看到一道算法题的时候,总是第一反应去想什么“巧”方法,但是在这个题目中实在是想不到,观察题目给出的限制,发现使用蛮力法的时候,复杂度也不是很大,算法思想为:
遍历一遍array数组,对于每一个元素array[i],求出array[i]的所有的子串,对于每一个子串sub,进行如下的处理:在array中除array[i]元素以外查找sub,如果都没有找到sub,说明sub符合题意。如果array[i]有多个子串满足题意,此时按照题目要求选择最短的。
考察算法最差情况下时间复杂度时先考察最基本语句也就是“在array中除array[i]元素以外查找sub”的执行次数最多为:
其中n=100,max=20则上面式子计算出来的值大概为1_000_000,大概100万次左右,其中查找操作调用C++里面提供的find函数,其实现基于KMP,执行次数最多为n+max也就是120次。最后得到完整的执行次数为1_2000_0000也就是1亿两千万次。看起来很多,但实际上由于每次都是执行最简单的比较查找操作,实际上代码运行时间也还可以接收。
完整代码如下:
class Solution
{
public:
vector<string> shortestSubstrings(vector<string> &arr)
{
// 使用蛮力法
vector<string> answer;
for (int i = 0; i < arr.size(); i++)
{
string current = arr[i];
string result = "";
for (int j = 0; j < current.length(); j++)
{
for (int k = 0; j+k < current.length(); k++)
{
// 获得子串
string sub = current.substr(j,k+1);
// 在其他子串中查找
int flag = 0;
for (int m = 0; m < arr.size(); m++)
{
if(m==i)continue;
if (arr[m].find(sub) != string::npos)
{
// 在其他字符串中找到此时sub不满足条件
flag = 1;
break;
}
}
if (flag == 0)
{ // 找到之后按照字典序进行比较,优先选择小的
if (result == "")
result = sub;
else
{
if(result.length()>sub.length()){
result = sub;
}else if(result.length()==sub.length()){
result = result.compare(sub) < 0 ? result : sub;
}
}
}
}
}
answer.push_back(result);
}
return answer;
}
};
最终代码运行的平均时间为400ms左右也算是比较慢的。而算法占用的空间就很小。
确定算法
编码
代码调试
题后总结
核心技巧总结
未来展望
C++二维数组赋值的几种方式
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int count(int (*p)[2], int m)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", p[i][j]);
}
}
printf("\n");
}
int count(int **array, int m, int n)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
// printf("%d ", array[i][j]);
printf("%d ", *((int *)array + i * n + j));
}
}
printf("\n");
}
int count(int *array, int m, int n)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
printf("%d ", *(array + i * n + j));
}
}
}
int main()
{
int array[3][2] = {1, 2, 3, 4, 5, 6};
count((int **)array, 3, 2);
count(array, 3);
count((int *)array, 3, 2);
}