LeetCode 练习(一)

Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place.

这道题用后序遍历解,因为题目给出的例子是以后序展平的:1)若左右子树为空,返回根节点本身;2)若左子树不为空,处理左子树;3)若右子树不为空,处理右子树,并将展平后的右子树根节点拼接在左子树最后节点上;4)将拼接后的首节点挂在根节点右子树上。在递归时,可以返回最右节点,以免之后重复查找。

#include <iostream>

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Solution {

private:
	TreeNode *flattenRight(TreeNode *node) {
		if (!node->left && !node->right) return (node);
		
		if (node->left && !node->right) {
			node->right = node->left;
			node->left = NULL;
			return (this->flattenRight(node->right));
		}
		if (!node->left && node->right) {
			return (this->flattenRight(node->right));
		}
		if (node->left && node->right) {
			TreeNode *right = this->flattenRight(node->left);
			right->right = node->right;
			node->right = node->left;
			node->left = NULL;
			return (this->flattenRight(right->right));
		}
	}
	
public:
	void flatten(TreeNode *root) {
	
		if (root) this->flattenRight(root);
	}
};

 

Longest Consecutive Sequence 

Given an unsorted array of integers, find the length of the longest consecutive elements sequence.

题目要求在$O(n)$时间内求出给定集合里最常的连续整数子集。注意不是序列问题,所以子集的元素顺序可以打乱。对于乱序集合,几人要求$O(n)$,排序是不行的,因此考虑Hashtable。在Hashtable $H$中寻找包含元素$i$的连续元素集合,可以以$i$为中心,向递增和递减两个方向分别作探测,然后合并探测的长度。以递增方向为例,首先$i \in H$,然后考察$i + 1 \in H$是否成立,若成立则继续测试$i + 2$,以此类推直到$i + m \notin H$,则偶递增方向的长度是$m - 1$。由此若$i - n \notin H$可得出递减方向长度是$n - 1$,因此包含$i$的子集和的长度是$m + n - 1$。对$H$中每一个元素作如上操作,求得长度的最大值就是解。注意在上面的例子中,对于所有元素$k, k \in [i - n + 1, i + m - 1]$求出的长度都是$m + n - 1$,所以当找到一个连续子集后,可以从$H$中删除这个子集,这样保证每个元素仅被测试一次。

#include <vector>
#include <unordered_set>

class Solution {

private:
	int ascending(std::unordered_set<int> &set, int val) {
		int count = 0;
		while (set.count(++val)) {
			++count;
			set.erase(val);
		}
		return (count);
	}
	int descending(std::unordered_set<int> &set, int val) {
		int count = 0;
		while (set.count(--val)) {
			++count;
			set.erase(val);
		}
		return (count);
	}
	
public:
	int longestConsecutive(std::vector<int> &nums) {
	
		std::unordered_set<int> set;
		for (size_t i = 0; i < nums.size(); ++i) set.insert(nums[i]);
		
		int result = 0;
		for (size_t i = 0; i < nums.size(); ++i) {
			if (set.count(nums[i])) result = std::max(result,
					1 + this->ascending(set, nums[i]) + this->descending(set, nums[i]));
		}
	
		return (result);
	}
};

 

Maximum Subarray

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

和最大连续子序列问题差不多,但题目要求必须至少包含一个元素。

#include <climits>
#include <vector>

class Solution {
	
public:
	int maxSubArray(int array[], int n) {
		
		if (!array || !n) return (0);
		
		int sum = INT_MIN, cnt = 0;
		for (int i = 0; i < n; ++i) {
			if (array[i] > 0) {
				if (cnt < 0) cnt = array[i];
				else cnt += array[i];
			} else {
				if ((cnt += array[i]) < 0) cnt = array[i];
			}
			sum = std::max(sum, cnt);
		}
		
		return (sum);
	}
};

 

Binary Tree Maximum Path Sum

Given a binary tree, find the maximum path sum.

Path指树中任意两个节点间通过他们最小公共父节点的路径。对节点$n$,左子树节点到$n$的所有路径最大值,加上右子树节点到$n$的所有路径最大值,再加上$n$本身的值,就是节点$的最优解$。所有节点最优解的最大值就是本题的解。采用后序遍历递归,递归中返回到根节点最大路径。

#include <climits>

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};



class Solution {

private:
	int maxPathSum(TreeNode *node, int &sum) {
	
		if (!node->left && !node->right) {
			sum = std::max(sum, node->val);
			return (node->val);
		}
		
		int lmax = 0, rmax = 0;
		if (node->left) lmax = std::max(0, this->maxPathSum(node->left, sum));
		if (node->right) rmax = std::max(0, this->maxPathSum(node->right, sum));
		
		sum = std::max(sum, node->val + lmax + rmax);
		return (node->val + std::max(lmax, rmax));
	}

public:
	int maxPathSum(TreeNode *root) {
	
		if (!root) return (0);
		
		int result = INT_MIN;
		this->maxPathSum(root, result);
		
		return (result);
	}
};

 

Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s.

尝试用动态规划方法解。对于只有一个字符的串$s$,最小切割数为0。考虑往$s$添加一个字符记为$a_{i}$,我们得到切割数是$c_{i-1} + 1$。然后向前看一个字符,如果后缀$a_{i-1}a_{i}$是回文,那么得到切割数$c_{i-2} + 1$。以此类推,直到考虑了所有后缀,我们得到以$a_{i}$结尾的字符串的最小切割数为所有回文后缀切割数的最小值。注意每次处理后缀,最后会考虑到整个字串的情况,如果整个字串是回文,那么最小切割数就是0。给出状态转移方程如下:

$$c_{i} =
\begin{cases}
\max_{k=1}^{i-1} c_{k} + 1, & \text{if } c_{k+1} \cdots c_{i} \text{ is palindrome} \\
0, & \text{if } c_{1} \cdots c_{i} \text{ is palindrome}
\end{cases}$$

#include <string>
#include <vector>

class Solution {

private:
	bool isPalind(const char *str, int beg, int end) {
		const char *a = str + beg;
		const char *b = str + end - 1;
		while (a < b) if (*a++ != *b--) return (false);
		return (true);
	}

public:
	int minCut(const std::string &str) {

		int len = str.length();
		std::vector<int> cuts(len, 0);
		
		for (int i = 1; i < len; ++i) {
			cuts[i] = len;
			for (int j = i; j > 0; --j) {
				if (this->isPalind(str.data(), j, i + 1)) {
					cuts[i] = std::min(cuts[i], cuts[j-1] + 1);
				}
			}
			if (this->isPalind(str.data(), 0, i + 1)) cuts[i] = 0;
		}
		
		return (cuts.back());
	}
};

 

posted @ 2013-08-24 15:31  Nagao  阅读(265)  评论(0)    收藏  举报