第六节课:


题目一

在这里插入图片描述
使用前缀树。
代码实现:

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值