题目一
使用前缀树。
代码实现:
class TreeNode {
public:
string str;
map<string, TreeNode*>nextsMap;
TreeNode(string str) {
this->str = str;
}
};
class Trie {
public:
TreeNode* root;
Trie() {
this->root = new TreeNode("root");
}
vector<string> splitStr(string& s) {
vector<string>res;
string cur = "";
for (int i = 0; i < s.length(); i++) {
if(s[i]!='\\'){
cur += s[i];
}
else {
res.push_back(cur);
cur = "";
}
}
res.push_back(cur);
return res;
}
void insert(string& s) {
vector<string>strs = splitStr(s);
TreeNode* node = root;
for (int i = 0; i < strs.size(); i++) {
if (node->nextsMap.find(strs[i]) == node->nextsMap.end()) {
TreeNode* cur = new TreeNode(strs[i]);
node->nextsMap.insert({ strs[i],cur });
}
node = node->nextsMap[strs[i]];
}
}
string get2nSpace(int i) {
string s = "";
for (int j = 1; j <= 2 * (i - 1); j++) {
s += " ";
}
return s;
}
void print(TreeNode* head,int i) {
if (i != 0) {
cout << get2nSpace(i) << head->str << endl;
}
for (pair<string, TreeNode*> next : head->nextsMap) {
print(next.second, i + 1);
}
}
};
题目二
补充条件:按照中序遍历的顺序转化乘双向链表。
利用二叉树的递归套路:问子树要转化之后的头和尾
代码实现:
class Node {
public:
int val;
Node* left;
Node* right;
Node(int val) {
this->val = val;
this->left = nullptr;
this->right = nullptr;
}
};
class Info {
public:
Node* head;
Node* tail;
Info() {
this->head = nullptr;
this->tail = nullptr;
}
Info(Node* head, Node* tail) {
this->head = head;
this->tail = tail;
}
};
Info* convert(Node* head) {
if (head == nullptr) {
return new Info();
}
Node* h = head;
Node* t = head;
Info* leftData = convert(head->left);
Info* rightData = convert(head->right);
if (leftData->head != nullptr) {
h= leftData->head;
leftData->tail->right = head;
head->left = leftData->tail;
}
if (rightData->head != nullptr) {
t = rightData->tail;
rightData->head->left = head;
head->right = rightData->head;
}
return new Info(h, t);
}
题目三
利用二叉树的递归套路:问子树要其最大搜索二叉子树的头节点、节点数、最大值、最小值。
注意本题求的是最大搜索二叉子树,是子树,而不是结构。
代码实现:
class Node {
public:
int val;
Node* left;
Node* right;
Node(int val) {
this->val = val;
this->left = nullptr;
this->right = nullptr;
}
};
class Info {
public:
Node* head;
int num;
int minv;
int maxv;
Info(Node* head, int num, int minv, int maxv) {
this->head = head;
this->num = num;
this->minv = minv;
this->maxv = maxv;
}
};
Info* process(Node* head) {
if (head == nullptr) {
return new Info(nullptr, 0, INT_MAX, INT_MIN);
}
Info* ldata = process(head->left);
Info* rdata = process(head->right);
Node* h;
int num;
int minv;
int maxv;
if (ldata->head == head->left && rdata->head == head->right&&ldata->maxv<head->val&&rdata->minv>head->val) {
h = head;
num = ldata->num + rdata->num + 1;
minv = min(head->val, min(ldata->minv, rdata->minv));
maxv = max(head->val, max(ldata->maxv, rdata->maxv));
}
else {
if (ldata->num > rdata->num) {
return ldata;
}
else {
return rdata;
}
}
return new Info(h, num, minv, maxv);
}
题目四
子数组的最大累加和问题:
方法一:求原数组的前缀和数组,然后找出前缀和数组的最大最小值,二者相减得到答案。
方法二:初始化两个变量cur=0、max=系统最小;遍历数组,cur=cur+arr[i],如果cur大于max,更新max=cur,否则max不变;如果cur<0,令cur=0(max不更新);最后返回max
证明:首先,假设数组中无正数–>流程正确;如果数组中有正有负,找到的子数组是累加和最大的,并且是所有累加和最大的子数组中最长的。这种累加和最大且最长的子数组(假设下标从i到j)具有如下性质:1) 从i到i和j之间的任何位置的累加和>=0,如果小于0了,舍弃前面的这部分可以得到更大的累加和,与最大假设不符;2) 任何一个位置开始累加到i-1位置的累加和必<0,如果>=0了,添加上会得到更长的子数组,与最长假设不符。根据这两个性质,方法流程遍历到i-1位置,cur一定会重新置零之后再加i位置的值,并且由于性质1,max一定可以抓取到从i到j的累加和(最大的)。通过以上分析可得:方法流程是正确的,且得到的子数组不仅是累加和最大的,同时也是累加和最大的子数组中长度最长的。
假设答案法:首先假设出答案,任何分析答案具有的性质,设计算法流程保证答案可以找到。
代码实现:
int subArrMaxSum01(vector<int>& arr) {
if (arr.size() == 0) {
return 0;
}
vector<int>presum(arr.size());
presum[0] = arr[0];
for (int i = 1; i < arr.size(); i++) {
presum[i] = presum[i - 1] + arr[i];
}
int minv = presum[0];
int maxv = presum[0];
for (int i = 1; i < presum.size(); i++) {
maxv = max(maxv, presum[i]);
minv = min(minv, presum[i]);
}
return maxv - minv;
}
int subArrMaxSum02(vector<int>& arr) {
if (arr.size() == 0) {
return 0;
}
int maxv = INT_MIN;
int cur = 0;
for (int i = 0; i < arr.size(); i++) {
cur += arr[i];
if (cur > maxv) {
maxv = cur;
}
if (cur < 0) {
cur = 0;
}
}
return maxv;
}
题目五
假设包含矩阵的某几行且只包含矩阵的这几行,哪个子矩阵的累加和是最大的,依次遍历所有的可能,求最大即为结果
求单行矩阵的最大累加和直接用题目四的方法;求多行矩阵的最大累加和,将这些行压缩成一行(同一列相加,压缩数组的技巧),再用题目四中的方法
当看到子矩阵的问题,先想子数组是怎么办的,当把子数组的问题解决了,再看能不能用矩阵压缩的方式将子矩阵的问题变为子数组的问题
代码实现:
int subMatrixMaxSum(vector<vector<int>>M) {
if (M.size() == 0 || M[0].size() == 0) {
return 0;
}
int maxv = INT_MIN;
int cur = 0;
for (int i = 0; i < M.size(); i++) {
vector<int>arr(M[0].size());
for (int j = i; j < M.size(); j++) {
cur = 0;
for (int k = 0; k < M[0].size(); k++) {
arr[k] += M[j][k];
cur += arr[k];
maxv = max(maxv, cur);
cur = cur < 0 ? 0 : cur;
}
}
}
return maxv;
}