Monthly Archives: March 2017

LeetCode Minimum Absolute Difference in BST

LeetCode Minimum Absolute Difference in BST Given a binary search tree with non-negative values, find the minimum absolute difference between values of any two nodes. Example:

Input:
   1
    \
     3
    /
   2
Output:
1
Explanation:
The minimum absolute difference is 1, which is the difference between 2 and 1 (or between 2 and 3).
Note: There are at least two nodes in this BST.
求一棵二叉搜索树中任意两个节点数值之差的绝对值的最小值。 因为是BST,所以满足左子树<=根节点<=右子树。以根节点root为例,则最小的差可能有两个,一个是root减去左子树中的最大数,另一个是右子树中的最小数减去root,所以整体的最小值就是这两个最小值的最小值。 左子树中的最大数就是左子树中最右下端的叶子节点,右子树中的最小数就是右子树中最左下端的叶子节点。 然后递归的以左右孩子为根更新最小值。代码如下: [cpp] class Solution { public: int getMinimumDifference(TreeNode* root) { int l = INT_MIN, r = INT_MAX; int left_min = INT_MAX, right_min = INT_MAX; if (root->left) { TreeNode* left = root->left; while (left->right)left = left->right; left_min = min(root->val – left->val, getMinimumDifference(root->left)); } if (root->right) { TreeNode* right = root->right; while (right->left)right = right->left; right_min = min(right->val – root->val, getMinimumDifference(root->right)); } return min(left_min, right_min); } }; [/cpp] 本代码提交AC,用时19MS。 还有一种思路,因为是BST,所以其中序遍历的结果是升序的,得到有序数组之后,相邻两个数的差的最小值就是要求的结果。 实际上,我们可以不用完整求出其升序序列之后再计算差,只需要在每次中序遍历时,记住该节点的上一个节点,这样该节点的值减去上一节点的值就相当于有序数组中相邻两个数作差。 代码如下: [cpp] class Solution { private: long long m_nLast, m_nAns; void inorderTraverse(TreeNode* root) { if (!root)return; inorderTraverse(root->left); // 左 m_nAns = min(m_nAns, root->val – m_nLast); m_nLast = root->val; // 根 inorderTraverse(root->right); // 右 } public: Solution() { m_nLast = INT_MIN; m_nAns = INT_MAX; } int getMinimumDifference(TreeNode* root) { inorderTraverse(root); return m_nAns; } }; [/cpp] 本代码提交AC,用时16MS。注意因为可能出现x-INT_MIN导致int溢出,所以两个成员变量定义为long long。 参考:http://bookshadow.com/weblog/2017/02/26/leetcode-minimum-absolute-difference-in-bst/]]>

LeetCode Base 7

LeetCode Base 7 Given an integer, return its base 7 string representation. Example 1:

Input: 100
Output: "202"
Example 2:
Input: -7
Output: "-10"
Note: The input will be in range of [-1e7, 1e7].
本题要把10进制数转换为7进制数。 根据以往10进制转换为2进制的规则,使用短除法,不断的除2取余数,然后把所有余数反排就得到二进制结果了。 将10进制转换为7进制的方法也是一样,不断的除7取余,余数反排就好了。 代码如下: [cpp] class Solution { public: string convertToBase7(int num) { if(num == 0) return "0"; int num_cp = num < 0 ? -num : num; string ans = ""; while(num_cp != 0){ ans = to_string(num_cp % 7) + ans; num_cp /= 7; } if(num < 0) return "-" + ans; else return ans; } }; [/cpp] 本代码提交AC,用时3MS。]]>

LeetCode Reverse String II

LeetCode Reverse String II Given a string and an integer k, you need to reverse the first k characters for every 2k characters counting from the start of the string. If there are less than k characters left, reverse all of them. If there are less than 2k but greater than or equal to k characters, then reverse the first k characters and left the other as original. Example:

Input: s = "abcdefg", k = 2
Output: "bacdfeg"
Restrictions:
  1. The string consists of lower English letters only.
  2. Length of the given string and k will in the range [1, 10000]

LeetCode Reverse String的基础上,稍微增加了一点难度,要求每2k个字母逆序其前k个字母。当剩余字母少于k个时,都逆序。当剩余字母在k个~2k个之间时,逆序前k个。 直接借用STL的reverse函数,迭代器的结束位置为min(s.begin() + start + k,s.end()),因为string是线性存储的,其迭代器可以比较大小。 代码如下: [cpp] class Solution { public: string reverseStr(string s, int k) { int n = s.size(); for (int start = 0; start < n; start += 2 * k) { reverse(s.begin() + start, min(s.begin() + start + k,s.end())); } return s; } }; [/cpp] 本代码提交AC,用时9MS。]]>

LeetCode Relative Ranks

LeetCode Relative Ranks Given scores of N athletes, find their relative ranks and the people with the top three highest scores, who will be awarded medals: “Gold Medal”, “Silver Medal” and “Bronze Medal”. Example 1:

Input: [5, 4, 3, 2, 1]
Output: ["Gold Medal", "Silver Medal", "Bronze Medal", "4", "5"]
Explanation: The first three athletes got the top three highest scores, so they got "Gold Medal", "Silver Medal" and "Bronze Medal".
For the left two athletes, you just need to output their relative ranks according to their scores.
Note:
  1. N is a positive integer and won’t exceed 10,000.
  2. All the scores of athletes are guaranteed to be unique.

给定N个运动员的得分,要求输出他们的相对排序,前三名还需要颁发金银铜奖牌。 简单题,构造分数和下标的pair,然后对他们排序,得到相对排名之后,转换为string输出。 代码如下: [cpp] class Solution { public: vector<string> findRelativeRanks(vector<int>& nums) { vector<pair<int, int>> scores; int n = nums.size(); for (int i = 0; i < n; ++i)scores.push_back(pair<int, int>(nums[i], i)); sort(scores.begin(), scores.end(), greater<pair<int,int>>()); vector<string> ans(n, ""); vector<string> medals = { "Gold Medal", "Silver Medal", "Bronze Medal" }; for (int i = 0; i < min(3, n); ++i)ans[scores[i].second] = medals[i]; for (int i = 3; i < n; ++i)ans[scores[i].second] = to_string(i + 1); return ans; } }; [/cpp] 本代码提交AC,用时13MS。]]>

LeetCode Detect Capital

LeetCode Detect Capital Given a word, you need to judge whether the usage of capitals in it is right or not. We define the usage of capitals in a word to be right when one of the following cases holds:

  1. All letters in this word are capitals, like “USA”.
  2. All letters in this word are not capitals, like “leetcode”.
  3. Only the first letter in this word is capital if it has more than one letter, like “Google”.
Otherwise, we define that this word doesn’t use capitals in a right way. Example 1:
Input: "USA"
Output: True
Example 2:
Input: "FlaG"
Output: False
Note: The input will be a non-empty word consisting of uppercase and lowercase latin letters.
判断一个单词的大写形式是否正确,大写的规则有三:
  1. 所有字母都是大写
  2. 所有字母都是小写
  3. 首字母大写,剩余字母全小写
简单题,直接根据规则写代码就好。如果首字母是小写,则剩余字母要全是小写。如果首字母是大写,则剩余字母要么都是大写,要么都是小写。 代码如下: [cpp] class Solution { private: inline bool myisupper(const char& c) { return c >= ‘A’&&c <= ‘Z’; } public: bool detectCapitalUse(string word) { int n = word.size(); if (n == 1)return true; bool firstUpper = myisupper(word[0]); if (firstUpper) { bool second = myisupper(word[1]); for (int i = 2; i < n; ++i) { if (second != myisupper(word[i]))return false; } return true; } else { for (int i = 1; i < n; ++i) { if (myisupper(word[i]))return false; } return true; } } }; [/cpp] 本代码提交AC,用时12MS。 奇怪的是,我用系统的isupper遇到“USA”单词时会判断错误,但是用自己实现的myisupper就好了。 网上还有一种简洁的方法,统计单词中大写字母的个数upper_cnt,如果upper_cnt==0,说明全是小写,正确;如果upper_cnt==n,说明全是大写,正确;如果upper_cnt==1,且首字母是大写,也是正确;其他情况都是错误。逻辑清楚,代码简洁: [cpp] class Solution { public: bool detectCapitalUse(string word) { int n = word.size(), upper_cnt = 0; for (int i = 0; i < n; ++i) { if (isupper(word[i]))++upper_cnt; } if (upper_cnt == 0 || n == upper_cnt)return true; if (upper_cnt == 1 && isupper(word[0]))return true; return false; } }; [/cpp] 本代码提交AC,用时6MS。]]>

LeetCode Next Greater Element II

503. Next Greater Element II 503. Next Greater Element II

Given a circular array (the next element of the last element is the first element of the array), print the Next Greater Number for every element. The Next Greater Number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn’t exist, output -1 for this number.

Example 1:

Input: [1,2,1]
Output: [2,-1,2]
Explanation: The first 1's next greater number is 2; 
The number 2 can't find next greater number;
The second 1's next greater number needs to search circularly, which is also 2.

Note: The length of given array won’t exceed 10000. 503. Next Greater Element II


LeetCode Next Greater Element I的扩展,本题的数组可能包含重复元素,且是循环数组,即往右找到尾之后,可以接着从头开始找更大的数。 同样使用栈,只不过需要扫描两遍数组,且栈中保存的是元素下标,理解之后发现挺巧妙的。 比如nums = [9, 8, 7, 3, 2, 1, 6],第一遍循环之后,堆栈中从低到顶剩余的元素是9,8,7,6,此时再从头开始扫描一遍数组,9,发现栈顶是6,所以6的右边更大数是9,弹出6;栈顶是7,7的右边更大数也是9;同理8,弹栈;最后栈顶只剩9了。
代码如下:

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums)
    {
        int n = nums.size();
        vector<int> ans(n, -1);
        stack<int> idx;
        for (int i = 0; i < 2 * n; ++i) {
            while (!idx.empty() && nums[idx.top()] < nums[i % n]) {
                ans[idx.top()] = nums[i % n];
                idx.pop();
            }
            idx.push(i % n);
        }
        return ans;
    }
};

本代码提交AC,用时119MS。

LeetCode Next Greater Element I

LeetCode Next Greater Element I You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1‘s elements in the corresponding places of nums2. The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number. Example 1:

Input: nums1 = [4,1,2], nums2 = [1,3,4,2].
Output: [-1,3,-1]
Explanation:
    For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
    For number 1 in the first array, the next greater number for it in the second array is 3.
    For number 2 in the first array, there is no next greater number for it in the second array, so output -1.
Example 2:
Input: nums1 = [2,4], nums2 = [1,2,3,4].
Output: [3,-1]
Explanation:
    For number 2 in the first array, the next greater number for it in the second array is 3.
    For number 4 in the first array, there is no next greater number for it in the second array, so output -1.
Note:
  1. All elements in nums1 and nums2 are unique.
  2. The length of both nums1 and nums2 would not exceed 1000.

给定两个数组nums1和nums2,其中nums1是nums2的子集,两个数组中的都没有重复元素。现在要问nums1中的每个数在nums2中其右边第一个更大的数是什么。 比如Example 2中,nums1[0]=2,在nums2中2的右边有3和4,则第一个更大的数是3。 常规思路是对于nums1中的每个数,在nums2中找到位置,并在其右边搜索第一个比它的数。更好一点的解法是,对nums2中的每个数,建立数和下标的hash关系,这样对于nums1中的每个数,就能O(1)找到其在nums2中的位置,直接开始在其右边找更大的数,但是渐进复杂度都是O(n*m)。 代码如下: [cpp] class Solution { public: vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) { unordered_map<int, int> hash; for (int i = 0; i < nums.size(); ++i)hash[nums[i]] = i; vector<int> ans; for (int i = 0; i < findNums.size(); ++i) { int idx = hash[findNums[i]], ret = -1; for (int j = idx + 1; j < nums.size(); ++j) { if (nums[j] > findNums[i]) { ret = nums[j]; break; } } ans.push_back(ret); } return ans; } }; [/cpp] 本代码提交AC,用时9MS。 还有一种比较巧妙的解法,借助栈,用O(m)时间就可以得到nums2中所有数的其右边更大数。具体举例,比如Example 1中nums2 = [1,3,4,2],先不断压栈,遇到1,压栈;遇到3,发现栈顶原始1比3小,说明1的右边更大数是3,建立hash关系,把1弹栈,栈内没东西了,3进栈。 更极端一点,假设nums2 = [9, 8, 7, 3, 2, 1, 6],则从9~1都一直压栈,因为后面的数一直比栈顶元素小,当不了栈顶原始的右边更大数。当遇到6时,发现栈顶是1,则6可以当1的右边更大数,把1弹栈;又发现6比当前栈顶2大,又可以当2的右边更大数;如此不断弹栈,直到栈顶为7时,6压栈。此时9~7和6都没有右边更大数。对于没有右边更大树的数,其右边更大数赋值为-1。 代码如下: [cpp] class Solution { public: vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) { unordered_map<int, int> hash; stack<int> stk; for (int i = 0; i < nums.size(); ++i) { while (!stk.empty() && stk.top() < nums[i]) { hash[stk.top()] = nums[i]; stk.pop(); } stk.push(nums[i]); } vector<int> ans; for (int i = 0; i < findNums.size(); ++i) { if (hash.find(findNums[i]) == hash.end())ans.push_back(-1); else ans.push_back(hash[findNums[i]]); } return ans; } }; [/cpp] 本代码提交AC,用时12MS。]]>

LeetCode Keyboard Row

LeetCode Keyboard Row Given a List of words, return the words that can be typed using letters of alphabet on only one row’s of American keyboard like the image below.   American keyboard   Example 1:

Input: ["Hello", "Alaska", "Dad", "Peace"]
Output: ["Alaska", "Dad"]
Note:
  1. You may use one character in the keyboard more than once.
  2. You may assume the input string will only contain letters of alphabet.

给定一个单词数组,问哪些单词可以只由键盘上同一行的字母构成。 简单题,把同一行的字母Hash到同一个值,然后判断单词中不同字母的Hash值是否相同,如果相同则正确,否则不正确。 因为单词只包含大小写字母,所以可以用26长的数组实现Hash功能。代码如下: [cpp] class Solution { private: vector<int> hash; void init() { hash.resize(26); hash[‘q’ – ‘a’] = hash[‘w’ – ‘a’] = hash[‘e’ – ‘a’] = hash[‘r’ – ‘a’] = hash[‘t’ – ‘a’] = hash[‘y’ – ‘a’] = hash[‘u’ – ‘a’] = hash[‘i’ – ‘a’] = hash[‘o’ – ‘a’] = hash[‘p’ – ‘a’] = 1; hash[‘a’ – ‘a’] = hash[‘s’ – ‘a’] = hash[‘d’ – ‘a’] = hash[‘f’ – ‘a’] = hash[‘g’ – ‘a’] = hash[‘h’ – ‘a’] = hash[‘j’ – ‘a’] = hash[‘k’ – ‘a’] = hash[‘l’ – ‘a’] = 2; hash[‘z’ – ‘a’] = hash[‘x’ – ‘a’] = hash[‘c’ – ‘a’] = hash[‘v’ – ‘a’] = hash[‘b’ – ‘a’] = hash[‘n’ – ‘a’] = hash[‘m’ – ‘a’] = 3; } public: vector<string> findWords(vector<string>& words) { init(); vector<string> ans; for (int i = 0; i < words.size(); ++i) { int id = 0; bool good = true; for (int j = 0; j < words[i].size(); ++j) { char c = tolower(words[i][j]); if (id != 0 && hash[c - 'a'] != id) { good = false; break; } id = hash[c - 'a']; } if (good)ans.push_back(words[i]); } return ans; } }; [/cpp] 本代码提交AC,用时0MS。]]>

LeetCode Summary Ranges

228. Summary Ranges2

Given a sorted integer array without duplicates, return the summary of its ranges.

Example 1:

Input:  [0,1,2,4,5,7]
Output: ["0->2","4->5","7"]
Explanation: 0,1,2 form a continuous range; 4,5 form a continuous range.

Example 2:

Input:  [0,2,3,4,6,8,9] Output: ["0","2->4","6","8->9"] Explanation: 2,3,4 form a continuous range; 8,9 form a continuous range.28. Summary Ranges

给定一个数组,把数组汇总成若干个连续的区间,以字符串的形式给出。
方法是判断两个相邻的数之差是否为1,不是1则前面的构成一个区间,转换为字符串输出。判断前一个区间只有一个数还是有多个数的方法是区间的起止位置i,j是否相差1,如果是,则只有一个数,否则有多个数。
注意最后一个区间需要在while循环外部判断。代码如下:

class Solution {
public:
    vector<string> summaryRanges(vector<int>& nums)
    {
        vector<string> ans;
        int n = nums.size(), i = 0, j = 1;
        if (n == 0)
            return ans;
        while (j < n) {
            if (nums[j] – nums[j – 1] == 1)
                ++j;
            else {
                if (j – i == 1)
                    ans.push_back(to_string(nums[i]));
                else
                    ans.push_back(to_string(nums[i]) + "->" + to_string(nums[j – 1]));
                i = j++;
            }
        }
        if (j – i == 1)
            ans.push_back(to_string(nums[i]));
        else
            ans.push_back(to_string(nums[i]) + "->" + to_string(nums[j – 1]));
        return ans;
    }
};

本代码提交AC,用时0MS。
还有一种解法利用了二分查找的思路,很有意思,参考讨论区
假如给定的数组是[1,2,3,4,5,…,10000,20000],如果还是用上述方法,时间复杂度是O(n),至少需要遍历一遍数组。但是数组的前10000个数是严格有序且连续递增的,如果能把这一部分识别出来,直接转换为”1->10000″,则速度会大大提高。
二分查找的思路是,对于给定区间[a,…,b],假设其在数组中的下标起点分别为[i,…,j],则如果b-a==j-i,说明[a,b]之间是类似上面的[1,2,…,10000]的情况的,因为数组中没有重复元素,所以区间有j-i个元素,且元素最大值和最小值的差b-a也是j-i,说明他们是一个连续的有序区间,我们直接把这个区间转换为”a->b”。
否则如果j-i!=b-a,则取中点mid=(i+j)/2,递归在[i,mid]和[mid+1,j]进行。
有一种情况需要注意的是,分割出来的区间可能需要合并,比如[1,2,3,4,5,6,8],初始i[1,..,8]不满足b-a==j-i,所以递归在[1,2,3,4]和[5,6,8]进行。左边转换为了”1->4″,右边还需要递归,假设转换为了”5->6″和”8″,那么”1->4″和”5->6″是需要合并的。所以我们在插入”5->6″时,看看之前得到的区间”1->4″的end是否和当前区间”5->6″的start只差1,如果是,则需要合并,更新之前区间的end为现在要插入区间的end,变成了”1->6″。
完整代码如下:

class Solution {
private:
    struct Range {
        int start, end;
        Range(int s, int e)
            : start(s)
            , end(e){};
    };
    void add2Ans(int a, int b, vector<Range>& ranges)
    {
        if (ranges.empty() || ranges[ranges.size() – 1].end != a – 1) {
            ranges.push_back(Range(a, b));
        }
        else {
            ranges[ranges.size() – 1].end = b;
        }
    }
    void helper(vector<int>& nums, int start, int end, vector<Range>& ranges)
    {
        if (start == end || end – start == nums[end] – nums[start]) {
            add2Ans(nums[start], nums[end], ranges);
            return;
        }
        int mid = start + (end – start) / 2;
        helper(nums, start, mid, ranges); // 先左区间
        helper(nums, mid + 1, end, ranges); // 后右区间
    }

public:
    vector<string> summaryRanges(vector<int>& nums)
    {
        vector<string> ans;
        if (nums.empty())
            return ans;
        vector<Range> ranges;
        helper(nums, 0, nums.size() – 1, ranges);
        for (const auto& r : ranges) {
            if (r.start == r.end)
                ans.push_back(to_string(r.start));
            else
                ans.push_back(to_string(r.start) + "->" + to_string(r.end));
        }
        return ans;
    }
};

本代码提交AC,用时0MS。
这个代码在数据有很多连续区间时,接近O(lgn)的复杂度。但是当数据全是不连续的时,比如[1,3,5,7,9],则只有到递归到最深层start==end(即针对单个数字)时,才得到一个区间,所以退化为O(n)的算法。
如果再follow up可能有重复元素时,上述二分查找的方法就不管用了,因为属于一个区间的不一定满足b-a==j-i,比如[1,2,2,2,3],b-a=2,而j-i=4。此时只能用第一种O(n)的方法:

class Solution {
public:
    vector<string> summaryRanges(vector<int>& nums)
    {
        vector<string> ans;
        if (nums.empty())
            return ans;
        int i = 0, j = 1, n = nums.size();
        while (j < n) {
            while (j < n && (nums[j] == nums[j – 1] || nums[j] – nums[j – 1] == 1))
                ++j; // 考虑重复元素
            if (j >= n)
                break;
            if (j – 1 == i)
                ans.push_back(to_string(nums[i]));
            else
                ans.push_back(to_string(nums[i]) + "->" + to_string(nums[j – 1]));
            i = j++;
        }
        if (j – 1 == i)
            ans.push_back(to_string(nums[i]));
        else
            ans.push_back(to_string(nums[i]) + "->" + to_string(nums[j – 1]));
        return ans;
    }
};

本代码提交AC,用时0MS。

二刷。更加鲁邦容易理解的代码:

class Solution {
public:
	vector<string> summaryRanges(vector<int>& nums) {
		vector<vector<int>> ranges;
		int i = 0, n = nums.size();
		while (i < n) {
			int j = i + 1;
			while (j < n&&nums[j] == nums[j - 1] + 1)++j;
			ranges.push_back({ nums[i],nums[j - 1] });
			i = j;
		}
		vector<string> ans;
		for (int i = 0; i < ranges.size(); ++i) {
			if (ranges[i][0] == ranges[i][1]) {
				ans.push_back(to_string(ranges[i][0]));
			}
			else {
				ans.push_back(to_string(ranges[i][0]) + "->" + to_string(ranges[i][1]));
			}
		}
		return ans;
	}
};

本代码提交AC,用时0MS。

LeetCode Rectangle Area

223. Rectangle Area 223. Rectangle Area

Find the total area covered by two rectilinear rectangles in a 2D plane.

Each rectangle is defined by its bottom left corner and top right corner as shown in the figure.

Rectangle Area

Example:

Input: A = -3, B = 0, C = 3, D = 4, E = 0, F = -1, G = 9, H = 2
Output: 45

Note:

Assume that the total area is never beyond the maximum possible value of int. 223. Rectangle Area


给定两个矩形,要求这两个矩形的面积和,如果有重叠区域,需要减去重叠区域的面积。因为这两个矩形的关系是rectilinear的,也就是像图中互相平行分布的,不会出现一个矩形斜着和另一个矩形相交(这样重叠区域可能是三角形或梯形)。 此题的难点是怎样判断两个矩形是否相交,肉眼很容易判断,但是怎样写一个通用程序呢。我原来的思路是先判断哪个矩形面积更小,然后判断小面积矩形是否有顶点落在大面积矩形内部,如果有则相交,否则不想交。 网上有一种比较简单的判断方法,它不判断两个矩形是否相交,而是判断两个矩形是否不相交,方法是判断一个矩形是否完全落在另一个矩形的上、下、左、右侧。因为矩形是rectilinear的,所以每侧判断只需一语句就行,比如判断图中右边那个矩形是否完全在左边矩形的右边,只需判断E>=C是否成立。 还有一种判断方法是,把两个矩形的顶点分别投影到x轴和y轴,如果投影到两个轴上的两条线段都不相交,则矩形没有重叠。 重叠之后求交集区域的面积也不难,比如上图,交集矩形x轴左端点是A,E的较大值,右端点是C,G的较小值,y轴类似。 完整代码如下:

class Solution {
public:
    int computeArea(int A, int B, int C, int D, int E, int F, int G, int H)
    {
        int area = (C – A) * (D – B) + (G – E) * (H – F);
        if (E >= C || // 右
            H <= B || // 下
            G <= A || // 左
            F >= D) // 上
            return area;
        return area – (min(C, G) – max(A, E)) * (min(D, H) – max(B, F));
    }
};

本代码提交AC,用时22MS。

二刷。方法相同,代码如下:

typedef long long ll;
class Solution {
public:
	int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
		ll area1 = (C - A)*(D - B);
		ll area2 = (G - E)*(H - F);
		ll area3 = 0;
		if (E >= C || F >= D || G <= A || H <= B) {
			//没有重叠
		}
		else {
			int ae = max(A, E), cg = min(C, G);
			int bf = max(B, F), dh = min(D, H);
			area3 = abs(cg - ae)*abs(dh - bf);
		}
		return area1 + area2 - area3;
	}
};

本代码提交AC,用时12MS。