Tag Archives: Hash

剑指 Offer 07. 重建二叉树

剑指 Offer 07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

3

/ \
9 20
/ \
15 7
 

限制:

0 <= 节点个数 <= 5000

注意:本题与主站 105 题重复:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


给定二叉树的前序和中序遍历,要求重构出原始二叉树。

前序:根、左、右;中序:左、根、右。所以每次把前序数组的第一个元素作为根节点,然后在中序中找到根节点,把中序划分为两半,由此可知道左、右子树子数组的长度,据此把前序也划分为左、右两部分,递归调用。为了快速找到根节点在中序数组中的位置,提前用hash表存储。完整代码如下:

class Solution {
private:
    TreeNode* buildTree(vector<int>& preorder, int pl, int pr, vector<int>& inorder, int il, int ir, unordered_map<int,int> &hash) {
        if(pr < pl || ir < il) return NULL;
        TreeNode *root = new TreeNode(preorder[pl]);
        int im = hash[preorder[pl]];
        int len_left = im - il, len_right = ir - im;
        root->left = buildTree(preorder, pl + 1, pl + len_left, inorder, il, im - 1, hash);
        root->right = buildTree(preorder, pl + len_left + 1, pr, inorder, im + 1, ir, hash);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        unordered_map<int,int> hash;
        for(int i = 0; i < inorder.size(); ++i) hash[inorder[i]] = i;

        int n = preorder.size();
        return buildTree(preorder, 0, n - 1, inorder, 0, n - 1, hash);
    }
};

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

LeetCode Maximum Number of Non-Overlapping Subarrays With Sum Equals Target

1546. Maximum Number of Non-Overlapping Subarrays With Sum Equals Target

Given an array nums and an integer target.

Return the maximum number of non-empty non-overlapping subarrays such that the sum of values in each subarray is equal to target.

Example 1:

Input: nums = [1,1,1,1,1], target = 2
Output: 2
Explanation: There are 2 non-overlapping subarrays [1,1,1,1,1] with sum equals to target(2).

Example 2:

Input: nums = [-1,3,5,1,4,2,-9], target = 6
Output: 2
Explanation: There are 3 subarrays with sum equal to 6.
([5,1], [4,2], [3,5,1,4,2,-9]) but only the first 2 are non-overlapping.

Example 3:

Input: nums = [-2,6,6,3,5,4,1,2,8], target = 10
Output: 3

Example 4:

Input: nums = [0,0,0], target = 0
Output: 3

Constraints:

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4
  • 0 <= target <= 10^6

给定一个数组,问数组中最多有多少个不overlap的子数组,它们的和等于target。

常规DP方法,假设dp[i]表示[0,…,i]能找到的最多的子串数目,则对于nums[i+1],如果从i+1往前,求累加和,如果累加到j的地方,累加和[j,…,i]等于target,则dp[i+1]=dp[j-1]+1。

这种思路的代码如下,需要注意for循环需要满足dp[j]==dp[i],如果dp[j]<dp[i],说明j已经回退到上一个累加和等于target的区间,已经有overlap了,需要终止。

class Solution {
public:
    int maxNonOverlapping(vector<int>& nums, int target) {
        int n = nums.size();
        vector<int> dp(n + 1, 0);
        for(int i = 1; i <= n; ++i) {
            dp[i] = dp[i - 1];
            int sum = 0;
            for(int j = i; j > 0 && dp[j] == dp[i]; --j) {
                sum += nums[j - 1];
                if(sum == target) dp[i] = max(dp[i], dp[j - 1] + 1);
            }
        }
        return dp[n];
    }
};

上述代码的时间复杂度为O(n^2),在最后几个大数据集上TLE。

参考评论区,用一个hash记录某个前缀和出现的最新下标,对于任意一个数nums[i],看看prefix_sum-target是否在之前记录的前缀和中(查hash即可),如果在,假设对应下标为j,则说明[j,…,i]之间的累加和等于target,找到一个。不过为了保证不overlap,需要保证下标j不能回退到上一个合法的累加和区间内,每次找到一个合法区间后,用right_most记录其右边界,下次只需要用j和right_most比较大小即可。

完整代码如下:

class Solution {
public:
    int maxNonOverlapping(vector<int>& nums, int target) {
        int n = nums.size();
        unordered_map<int, int> hash;
        hash[0] = -1;
        int prefix_sum = 0, right_most = -1;
        int ans = 0;
        for(int i = 0; i < n; ++i) {
            prefix_sum += nums[i];
            int supplement = prefix_sum - target;
            if(hash.find(supplement) != hash.end()) {
                int left = hash[supplement];
                if(left >= right_most) {
                    ++ans;
                    right_most = i;
                }
            }
            hash[prefix_sum] = i;
        }
        return ans;
    }
};

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

剑指 Offer 03. 数组中重复的数字

剑指 Offer 03. 数组中重复的数字

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
 

限制:

2 <= n <= 100000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


查找数组中的重复元素。直接用数组hash,代码如下:

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int n = nums.size();
        vector<int> hash(n, 0);
        for(int i = 0; i < n; ++i) {
            ++hash[nums[i]];
            if(hash[nums[i]] > 1) {
                return nums[i];
            }
        }
        return 0;
    }
};

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

二刷。这题有陷阱,请注意和Find the Duplicate Number不一样!Leetcode英文题中,数组长度是n+1,数的范围是[1,n],也就是说根据鸽巢原理,数组必定有一个重复元素。而本题中,数组长度是n,数的范围是[0,n-1],也就是说数组可以没有重复元素,只不过这题告诉你至少有一个重复元素,要找出来。

这题不能用英文题中的二分的方法,比如n=6数组[0,0,2,3,4,5],l=0,r=5,m=2,统计[0,2]区间的数的个数=3,满足3<=m+1,因为即使是无重复数组[0,1,2,3,4,5],也是3<=m+1,所以无法区分左边区间是否有重复。

看题解,O(1)的方法是。如果数组没有重复元素,则排序之后nums[i]=i,所以我们模拟排序的过程,遍历数组,如果nums[i]!=i,则把nums[i]放到它排序后应该在的位置,即放到nums[nums[i]]的位置。如果nums[i]和它要放的位置nums[nums[i]]相等,说明这个元素重复出现了。完整代码如下:

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int n = nums.size();
        for(int i = 0; i < n; ++i) {
            while(nums[i] != i) {
                if(nums[i] == nums[nums[i]]) return nums[i];
                swap(nums[i],nums[nums[i]]);
            }
        }
        return 0;
    }
};

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

LeetCode Avoid Flood in The City

1488. Avoid Flood in The City

Your country has an infinite number of lakes. Initially, all the lakes are empty, but when it rains over the nth lake, the nth lake becomes full of water. If it rains over a lake which is full of water, there will be a flood. Your goal is to avoid the flood in any lake.

Given an integer array rains where:

  • rains[i] > 0 means there will be rains over the rains[i] lake.
  • rains[i] == 0 means there are no rains this day and you can choose one lake this day and dry it.

Return an array ans where:

  • ans.length == rains.length
  • ans[i] == -1 if rains[i] > 0.
  • ans[i] is the lake you choose to dry in the ith day if rains[i] == 0.

If there are multiple valid answers return any of them. If it is impossible to avoid flood return an empty array.

Notice that if you chose to dry a full lake, it becomes empty, but if you chose to dry an empty lake, nothing changes. (see example 4)

Example 1:

Input: rains = [1,2,3,4]
Output: [-1,-1,-1,-1]
Explanation: After the first day full lakes are [1]
After the second day full lakes are [1,2]
After the third day full lakes are [1,2,3]
After the fourth day full lakes are [1,2,3,4]
There's no day to dry any lake and there is no flood in any lake.

Example 2:

Input: rains = [1,2,0,0,2,1]
Output: [-1,-1,2,1,-1,-1]
Explanation: After the first day full lakes are [1]
After the second day full lakes are [1,2]
After the third day, we dry lake 2. Full lakes are [1]
After the fourth day, we dry lake 1. There is no full lakes.
After the fifth day, full lakes are [2].
After the sixth day, full lakes are [1,2].
It is easy that this scenario is flood-free. [-1,-1,1,2,-1,-1] is another acceptable scenario.

Example 3:

Input: rains = [1,2,0,1,2]
Output: []
Explanation: After the second day, full lakes are  [1,2]. We have to dry one lake in the third day.
After that, it will rain over lakes [1,2]. It's easy to prove that no matter which lake you choose to dry in the 3rd day, the other one will flood.

Example 4:

Input: rains = [69,0,0,0,69]
Output: [-1,69,1,1,-1]
Explanation: Any solution on one of the forms [-1,69,x,y,-1], [-1,x,69,y,-1] or [-1,x,y,69,-1] is acceptable where 1 <= x,y <= 10^9

Example 5:

Input: rains = [10,20,20]
Output: []
Explanation: It will rain over lake 20 two consecutive days. There is no chance to dry any lake.

Constraints:

  • 1 <= rains.length <= 10^5
  • 0 <= rains[i] <= 10^9

给定一个数组rains,rains[i]表示第i天在第rains[i]的湖上下雨,湖被灌满,比如第四个例子,rains[0]=69表示第0天在第69号湖上下雨,第69号湖被灌满。如果rains[i]=0表示第i天不下雨,可以抽干某个湖。问每个不下雨的天,抽干哪个湖,能让任意一个湖都不至于出现水灾(被灌满之后又被下雨)。

很有意思的一个题,暴力方法是,每个不下雨的天,对于之前被灌满的湖,抽干未来第一个要下雨的湖。比如对于rains=[1,2,3,0,2,0,0],当遇到第一个0时,我们选择抽干2号湖,因为下一天马上要在2号湖上下雨,如果不抽干2号湖,则会发生水灾,所以要抽干未来第一个要出现水灾的湖。但是这种时间复杂度是O(n^2)。

参考讨论区,更好的做法是,先记录所有不下雨的天,然后对于每一个下雨天,如果要下雨的湖之前没被灌满,则不用管;如果之前被灌满了,则需要在之前被灌满那天之后找一个不下雨的天,把这个湖抽干。所以维护一个堆heap/set,记录之前不下雨的天,后续直接用lower_bound查找符合的天。

完整代码如下:

class Solution {
public:
	vector<int> avoidFlood(vector<int>& rains) {
		int n = rains.size();

		vector<int> ans;
		unordered_map<int, int> full_lakes;
		set<int> dry_days;

		for (int i = 0; i < n; ++i) {
			if (rains[i] == 0) {
				dry_days.insert(i);
				ans.push_back(1); // 先随便填一个数,后续会覆盖,填入真正要抽干的湖编号
			}
			else {
				if (full_lakes.find(rains[i]) != full_lakes.end()) { // 这个湖之前就满了,需要抽干
					int last_day = full_lakes[rains[i]];
					set<int>::iterator it = dry_days.lower_bound(last_day); //从之前满的那天往后选不下雨的一天抽干
					if (it == dry_days.end()) {
						return {}; // 失败
					}
					ans[*it] = rains[i];
					dry_days.erase(it);
				}
				full_lakes[rains[i]] = i; // 填入新的下雨日期
				ans.push_back(-1);
			}
		}

		return ans;
	}
};

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

LeetCode Making File Names Unique

1487. Making File Names Unique

Given an array of strings names of size n. You will create n folders in your file system such that, at the ith minute, you will create a folder with the name names[i].

Since two files cannot have the same name, if you enter a folder name which is previously used, the system will have a suffix addition to its name in the form of (k), where, k is the smallest positive integer such that the obtained name remains unique.

Return an array of strings of length n where ans[i] is the actual name the system will assign to the ith folder when you create it.

Example 1:

Input: names = ["pes","fifa","gta","pes(2019)"]
Output: ["pes","fifa","gta","pes(2019)"]
Explanation: Let's see how the file system creates folder names:
"pes" --> not assigned before, remains "pes"
"fifa" --> not assigned before, remains "fifa"
"gta" --> not assigned before, remains "gta"
"pes(2019)" --> not assigned before, remains "pes(2019)"

Example 2:

Input: names = ["gta","gta(1)","gta","avalon"]
Output: ["gta","gta(1)","gta(2)","avalon"]
Explanation: Let's see how the file system creates folder names:
"gta" --> not assigned before, remains "gta"
"gta(1)" --> not assigned before, remains "gta(1)"
"gta" --> the name is reserved, system adds (k), since "gta(1)" is also reserved, systems put k = 2. it becomes "gta(2)"
"avalon" --> not assigned before, remains "avalon"

Example 3:

Input: names = ["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece"]
Output: ["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece(4)"]
Explanation: When the last folder is created, the smallest positive valid k is 4, and it becomes "onepiece(4)".

Example 4:

Input: names = ["wano","wano","wano","wano"]
Output: ["wano","wano(1)","wano(2)","wano(3)"]
Explanation: Just increase the value of k each time you create folder "wano".

Example 5:

Input: names = ["kaido","kaido(1)","kaido","kaido(1)"]
Output: ["kaido","kaido(1)","kaido(2)","kaido(1)(1)"]
Explanation: Please note that system adds the suffix (k) to current name even it contained the same suffix before.

Constraints:

  • 1 <= names.length <= 5 * 10^4
  • 1 <= names[i].length <= 20
  • names[i] consists of lower case English letters, digits and/or round brackets.

给定一个字符串数组,表示每次创建的文件名,如果新的文件名和之前的文件名重名,则需要在后面加上最小的(k)重命名。问最终创建的文件名数组是怎样的。

使用hash表记录每个文件名前缀出现的次数,如果之前没出现,则直接合法;如果之前出现了,则合法的(k)至少是之前出现次数之后的k,枚举找到最小的k。代码如下:

class Solution {
public:
	vector<string> getFolderNames(vector<string>& names) {
		vector<string> ans;
		unordered_map<string, int> show_times;
		for (int i = 0; i < names.size(); ++i) {
			if (show_times.find(names[i]) == show_times.end()) {
				ans.push_back(names[i]);
				show_times[names[i]] = 1;
			}
			else {
				int k = show_times[names[i]];
				string next_name = names[i] + "(" + to_string(k) + ")";
				while (show_times.find(next_name) != show_times.end()) {
					show_times[names[i]] = ++k;
					next_name = names[i] + "(" + to_string(k) + ")";
				}
				ans.push_back(next_name);
				show_times[next_name] = 1;
			}
		}
		return ans;
	}
};

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

LeetCode Minimum Number of Days to Make m Bouquets

5455. Minimum Number of Days to Make m Bouquets

Given an integer array bloomDay, an integer m and an integer k.

We need to make m bouquets. To make a bouquet, you need to use k adjacent flowers from the garden.

The garden consists of n flowers, the ith flower will bloom in the bloomDay[i] and then can be used in exactly one bouquet.

Return the minimum number of days you need to wait to be able to make m bouquets from the garden. If it is impossible to make m bouquets return -1.

Example 1:

Input: bloomDay = [1,10,3,10,2], m = 3, k = 1
Output: 3
Explanation: Let's see what happened in the first three days. x means flower bloomed and _ means flower didn't bloom in the garden.
We need 3 bouquets each should contain 1 flower.
After day 1: [x, _, _, _, _]   // we can only make one bouquet.
After day 2: [x, _, _, _, x]   // we can only make two bouquets.
After day 3: [x, _, x, _, x]   // we can make 3 bouquets. The answer is 3.

Example 2:

Input: bloomDay = [1,10,3,10,2], m = 3, k = 2
Output: -1
Explanation: We need 3 bouquets each has 2 flowers, that means we need 6 flowers. We only have 5 flowers so it is impossible to get the needed bouquets and we return -1.

Example 3:

Input: bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
Output: 12
Explanation: We need 2 bouquets each should have 3 flowers.
Here's the garden after the 7 and 12 days:
After day 7: [x, x, x, x, _, x, x]
We can make one bouquet of the first three flowers that bloomed. We cannot make another bouquet from the last three flowers that bloomed because they are not adjacent.
After day 12: [x, x, x, x, x, x, x]
It is obvious that we can make two bouquets in different ways.

Example 4:

Input: bloomDay = [1000000000,1000000000], m = 1, k = 1
Output: 1000000000
Explanation: You need to wait 1000000000 days to have a flower ready for a bouquet.

Example 5:

Input: bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
Output: 9

Constraints:

  • bloomDay.length == n
  • 1 <= n <= 10^5
  • 1 <= bloomDay[i] <= 10^9
  • 1 <= m <= 10^6
  • 1 <= k <= n

花园里有n朵花,告诉你每朵花在第几天开花。现在要扎m束花,每束花必须由相邻的k朵花组成,问要完成这个任务,最少需要等多少天。

首先看看需要的总花数m*k是否>n,如果是的话,即使所有花都开了也无法完成任务。

对于能够完成的任务,要求最少等待天数。暴力方法是,枚举bloomDay数组中所有unique的天数,对于每一天,都看看能否完成任务,方法是把数组中相邻的开的花每k多组成一束,看看能否组成m束。

但是暴力方法超时,一个改进的方法是二分。因为天数是递增的,而且每增加一天,开花的总数也是递增的,相当于能组成的花束也是递增的(严格来说是非递减的),这就为二分搜索创造了条件。

维护两个数组,days存储了unique的天数,递增排序(map自动递增有序了);num_bloomed表示在当前天数下,开花的总数,随着days的增大, num_bloomed 存储的开花总数也是递增的。在构造 num_bloomed 的过程中,可以求到最小的可能的开始天数left,然后在left和right中二分搜索合法的最小天数。

完整代码如下:

class Solution {
	bool IsValid(vector<int>& bloomDay, int day, int m, int k) {
		int bouquets = 0, n = bloomDay.size();
		int i = 0, good = 0;
		while (i < n) {
			while (i<n&&bloomDay[i]>day)++i;
			if (i >= n)break;

			int j = i;
			while (j < n&&bloomDay[j] <= day)++j;
			// [i,j) 都开花了

			good += (j - i) / k;

			i = j;
		}
		return good >= m;
	}
public:
	int minDays(vector<int>& bloomDay, int m, int k) {
		int n = bloomDay.size();
		if (m*k > n)return -1;

		map<int, int> hash;
		for (int i = 0; i < n; ++i)++hash[bloomDay[i]];
		if (m*k == n)return (--hash.end())->first; // 最后一天

		int unique_day = hash.size();
		vector<int> days(unique_day, 0);
		vector<int> num_bloomed(unique_day, 0);

		int d = 0, nb = 0;
		int left = 0, right = unique_day - 1, found_left = false;
		for (map<int, int>::iterator it = hash.begin(); it != hash.end(); ++it) {
			nb += it->second;
			if (nb >= m * k && !found_left) {
				left = d;
				found_left = true;
			}

			days[d] = it->first;
			num_bloomed[d] = nb;
			
			++d;
		}

		while (left <= right) {
			int mid = left + (right - left) / 2;
			bool valid = IsValid(bloomDay, days[mid], m, k);
			if (valid)right = mid - 1;
			else left = mid + 1;
		}

		return days[right + 1];
	}
};

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

Leetcode Least Number of Unique Integers after K Removals

5454. Least Number of Unique Integers after K Removals

Given an array of integers arr and an integer k. Find the least number of unique integers after removing exactly k elements.

Example 1:

Input: arr = [5,5,4], k = 1
Output: 1
Explanation: Remove the single 4, only 5 is left.

Example 2:

Input: arr = [4,3,1,1,3,3,2], k = 3
Output: 2
Explanation: Remove 4, 2 and either one of the two 1s or three 3s. 1 and 3 will be left.

Constraints:

  • 1 <= arr.length <= 10^5
  • 1 <= arr[i] <= 10^9
  • 0 <= k <= arr.length

给定一个数组,问从中删掉K个数后,剩余数中unique数的个数最少是多少。

要让剩余的unique数最少,则删掉的数必须是频率最低的数。举个例子,原数组是[1,2,3,3,3],如果删掉两个数,肯定是删掉1,2,这样剩余是[3,3,3],unique数只有3这一个数。如果删掉两个3,则剩余[1,2,3],unique数有3个。

所以,对所有数按其频率从小到大排序,然后删掉频率最低的前几个数即可。完整代码如下:

class Solution {
public:
	int findLeastNumOfUniqueInts(vector<int>& arr, int k) {
		int n = arr.size();
		vector<pair<int, int>> num_counts;
		unordered_map<int, int> hash;
		for (int i = 0; i < n; ++i)++hash[arr[i]];
		for (unordered_map<int, int>::iterator it = hash.begin(); it != hash.end(); ++it) {
			num_counts.push_back(make_pair(it->second, it->first));
		}
		sort(num_counts.begin(), num_counts.end());
		int m = num_counts.size(), sum = 0;

		if (k == 0)return m;
		else if (k == n)return 0;

		for (int i = 0; i < m; ++i) {
			sum += num_counts[i].first;
			if (sum == k)return m - i - 1;
			else if (sum > k)return m - i;
		}

		return 0;
	}
};

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

LeetCode Destination City

5400. Destination City

You are given the array paths, where paths[i] = [cityAi, cityBi] means there exists a direct path going from cityAi to cityBiReturn the destination city, that is, the city without any path outgoing to another city.

It is guaranteed that the graph of paths forms a line without any loop, therefore, there will be exactly one destination city.

Example 1:

Input: paths = [["London","New York"],["New York","Lima"],["Lima","Sao Paulo"]]
Output: "Sao Paulo" 
Explanation: Starting at "London" city you will reach "Sao Paulo" city which is the destination city. Your trip consist of: "London" -> "New York" -> "Lima" -> "Sao Paulo".

Example 2:

Input: paths = [["B","C"],["D","B"],["C","A"]]
Output: "A"
Explanation: All possible trips are: 
"D" -> "B" -> "C" -> "A". 
"B" -> "C" -> "A". 
"C" -> "A". 
"A". 
Clearly the destination city is "A".

Example 3:

Input: paths = [["A","Z"]]
Output: "Z"

Constraints:

  • 1 <= paths.length <= 100
  • paths[i].length == 2
  • 1 <= cityAi.length, cityBi.length <= 10
  • cityA!= cityBi
  • All strings consist of lowercase and uppercase English letters and the space character.

给定一个路径数组,每条路径标明了出发城市和到达城市,问所有路径最终会到达哪个城市,最终到达的城市是只有进路,没有出路的城市。

简单题,统计下所有城市的入度和出度,出度为0的城市即为最终城市。

class Solution {
public:
	string destCity(vector<vector<string>>& paths) {
		map<string, pair<int,int>> count;
		for (int i = 0; i < paths.size(); ++i) {
			string src = paths[i][0], dest = paths[i][1];
			++count[src].first; // 出度
			++count[dest].second; // 入度
		}
		for (map<string, pair<int, int>>::iterator it = count.begin(); it != count.end(); ++it) {
			if (it->second.first == 0) {
				return it->first;
			}
		}
		return "";
	}
};

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

LeetCode First Unique Number

LeetCode First Unique Number

You have a queue of integers, you need to retrieve the first unique integer in the queue.

Implement the FirstUnique class:

  • FirstUnique(int[] nums) Initializes the object with the numbers in the queue.
  • int showFirstUnique() returns the value of the first unique integer of the queue, and returns -1 if there is no such integer.
  • void add(int value) insert value to the queue.

Example 1:

Input: 
["FirstUnique","showFirstUnique","add","showFirstUnique","add","showFirstUnique","add","showFirstUnique"]
[[[2,3,5]],[],[5],[],[2],[],[3],[]]
Output: 

[null,2,null,2,null,3,null,-1]

Explanation: FirstUnique firstUnique = new FirstUnique([2,3,5]); firstUnique.showFirstUnique(); // return 2 firstUnique.add(5); // the queue is now [2,3,5,5] firstUnique.showFirstUnique(); // return 2 firstUnique.add(2);            // the queue is now [2,3,5,5,2] firstUnique.showFirstUnique(); // return 3 firstUnique.add(3);            // the queue is now [2,3,5,5,2,3] firstUnique.showFirstUnique(); // return -1

Example 2:

Input: 
["FirstUnique","showFirstUnique","add","add","add","add","add","showFirstUnique"]
[[[7,7,7,7,7,7]],[],[7],[3],[3],[7],[17],[]]
Output: 

[null,-1,null,null,null,null,null,17]

Explanation: FirstUnique firstUnique = new FirstUnique([7,7,7,7,7,7]); firstUnique.showFirstUnique(); // return -1 firstUnique.add(7); // the queue is now [7,7,7,7,7,7,7] firstUnique.add(3);            // the queue is now [7,7,7,7,7,7,7,3] firstUnique.add(3);            // the queue is now [7,7,7,7,7,7,7,3,3] firstUnique.add(7);            // the queue is now [7,7,7,7,7,7,7,3,3,7] firstUnique.add(17);           // the queue is now [7,7,7,7,7,7,7,3,3,7,17] firstUnique.showFirstUnique(); // return 17

Example 3:

Input: 
["FirstUnique","showFirstUnique","add","showFirstUnique"]
[[[809]],[],[809],[]]
Output: 

[null,809,null,-1]

Explanation: FirstUnique firstUnique = new FirstUnique([809]); firstUnique.showFirstUnique(); // return 809 firstUnique.add(809); // the queue is now [809,809] firstUnique.showFirstUnique(); // return -1

Constraints:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^8
  • 1 <= value <= 10^8
  • At most 50000 calls will be made to showFirstUnique and add.

设计题。设计一个队列,能够快速返回当前队列中第一个unique的数。

和之前的LRU很类似,使用list+unordered_map实现。list保存当前unique的数,unordered_map保存每个unique的数在list中的迭代器。当插入一个数到队列中时,首先看看在不在unordered_map中,如果不在,说明这个数是unique的,插入list和unordered_map。如果在,则看看unordered_map中的迭代器,如果迭代器不为空,说明这个数之前是unique的,需要从list中删掉;否则说明这个数之前就已经不是unique的了,不做任何操作。

完整代码如下:

class FirstUnique {
private:
	list<int> uniques_;
	unordered_map<int, list<int>::iterator> hash;
public:
	FirstUnique(vector<int>& nums) {
		for (int i = 0; i < nums.size(); ++i) {
			add(nums[i]);
		}
	}

	int showFirstUnique() {
		if (uniques_.empty())return -1;
		else return uniques_.front();
	}

	void add(int value) {
		if (hash.find(value) == hash.end()) {
			uniques_.push_back(value);
			hash[value] = --uniques_.end();
		}
		else {
			if (hash[value] != uniques_.end()) {
				uniques_.erase(hash[value]);
				hash[value] = uniques_.end();
			}
		}
	}
};

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

LeetCode Counting Elements

LeetCode Counting Elements

Given an integer array arr, count element x such that x + 1 is also in arr.

If there’re duplicates in arr, count them seperately.

Example 1:

Input: arr = [1,2,3]
Output: 2
Explanation: 1 and 2 are counted cause 2 and 3 are in arr.

Example 2:

Input: arr = [1,1,3,3,5,5,7,7]
Output: 0
Explanation: No numbers are counted, cause there's no 2, 4, 6, or 8 in arr.

Example 3:

Input: arr = [1,3,2,3,5,0]
Output: 3
Explanation: 0, 1 and 2 are counted cause 1, 2 and 3 are in arr.

Example 4:

Input: arr = [1,1,2,2]
Output: 2
Explanation: Two 1s are counted cause 2 is in arr.

Constraints:

  • 1 <= arr.length <= 1000
  • 0 <= arr[i] <= 1000

给定一个数组,如果数组中某个元素x和x+1都存在,则计数加一,问数组中共有多少个这样的x。

简单题,直接用set记录下有哪些数,再遍历看看x+1是否存在即可。代码如下:

class Solution {
public:
	int countElements(vector<int>& arr) {
		set<int> unique_nums;
		for (int i = 0; i < arr.size(); ++i) {
			unique_nums.insert(arr[i]);
		}
		int ans = 0;
		for (int i = 0; i < arr.size(); ++i) {
			if (unique_nums.find(arr[i] + 1) != unique_nums.end())++ans;
		}
		return ans;
	}
};

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