Monthly Archives: March 2020

LeetCode Linked List in Binary Tree

1367. Linked List in Binary Tree

Given a binary tree root and a linked list with head as the first node. 

Return True if all the elements in the linked list starting from the head correspond to some downward path connected in the binary tree otherwise return False.

In this context downward path means a path that starts at some node and goes downwards.

Example 1:

Input: head = [4,2,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
Output: true
Explanation: Nodes in blue form a subpath in the binary Tree.  

Example 2:

Input: head = [1,4,2,6], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
Output: true

Example 3:

Input: head = [1,4,2,6,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
Output: false
Explanation: There is no path in the binary tree that contains all the elements of the linked list from head.

Constraints:

  • 1 <= node.val <= 100 for each node in the linked list and binary tree.
  • The given linked list will contain between 1 and 100 nodes.
  • The given binary tree will contain between 1 and 2500 nodes.

给定一棵二叉树和一个链表,问链表中的元素是否是二叉树中某一条向下的路径的一部分,结合题中的例子,很容易理解题意。

我的做法是,对于链表head和二叉树root,首先在root中找到所有值是head的节点,也就是找到树中的开始比对的节点。然后,链表中的节点和树中的节点递归比对,直到走完链表比对成功,或者出现不相等或树没有孩子节点,比对失败。

完整代码如下:

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;

 //Definition for singly-linked list.
struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x) : val(x), next(NULL) {}
};
 
//Definition for a binary tree node.
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
  
class Solution {
public:
	void findStartNodes(vector<TreeNode*> &starts, TreeNode* root, int val) {
		if (root->val == val)starts.push_back(root);
		if (root->left != NULL)findStartNodes(starts, root->left, val);
		if (root->right != NULL)findStartNodes(starts, root->right, val);
	}

	bool findSubPath(ListNode* head, TreeNode* root) {
		if (head->next == NULL) {
			return true;
		}
		else {
			bool left_ans = false, right_ans = false;
			if (root->left != NULL && root->left->val == head->next->val) {
				left_ans =  findSubPath(head->next, root->left);
			}
			if (root->right != NULL && root->right->val == head->next->val) {
				right_ans = findSubPath(head->next, root->right);
			}
			return left_ans || right_ans;
		}
	}

	bool isSubPath(ListNode* head, TreeNode* root) {
		vector<TreeNode*> starts;
		findStartNodes(starts, root, head->val);

		for (int i = 0; i < starts.size(); ++i) {
			if (findSubPath(head, starts[i]))return true;
		}

		return false;
	}
};

ListNode* genList(const vector<int> &vec) {
	if (vec.size() == 0)return NULL;
	ListNode* head = new ListNode(vec[0]);
	ListNode* cur = head;
	for (int i = 1; i < vec.size(); ++i) {
		ListNode* node = new ListNode(vec[i]);
		cur->next = node;
		cur = node;
	}
	return head;
}

// -1表示空节点
TreeNode* genTree(const vector<int> &vec) {
	if (vec.size() == 0)return NULL;

	vector<TreeNode*> nodes(vec.size(), NULL);
	for (int i = 0; i < vec.size(); ++i) {
		if (vec[i] != -1) {
			nodes[i] = new TreeNode(vec[i]);
		}
	}
	
	int npar = 0, nchild = 1;
	while (true) {
		if (nchild >= nodes.size())break;

		int nnextpar = nchild;
		while (npar < nnextpar) {
			if (nodes[npar] != NULL) {
				if (nchild >= nodes.size())break;
				nodes[npar]->left = nodes[nchild++];
				if (nchild >= nodes.size())break;
				nodes[npar]->right = nodes[nchild++];
			}
			++npar;
		}
		npar = nnextpar;
	}
	
	return nodes[0];
}


int main() {
	vector<int> vec = { 1,4,4,-1,2,2,-1,1,-1,6,8,-1,-1,-1,-1,1,3 };
	TreeNode* root = genTree(vec);

	vector<int> vec2 = { 1,4,2,6,8 };
	ListNode* head = genList(vec2);

	Solution s;
	bool ans = s.isSubPath(head, root);
	return 0;
}

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

之前在LeetCode Minimum Depth of Binary Tree中我曾写过一个genTree的辅助函数,根据数组生成对应的二叉树。但是那个函数要求二叉树是完全二叉树,如果二叉树残缺很多节点的话,构造数组很麻烦。比如用之前的函数构造此题示例的二叉树,则数组中需要添加很多-1,很麻烦而且容易出错。

借此题的机会,我重写了一个genTree的辅助函数,如上代码所示。这个构造函数方便很多,对于输入数组,每个节点的左右孩子依次追加在数组的后面,也不用为空节点的孩子保留-1。genTree的时候先构造好所有节点,然后根据规则把这些节点连接起来。具体使用方法可以看代码中的示例。

LeetCode Rank Teams by Votes

1366. Rank Teams by Votes

In a special ranking system, each voter gives a rank from highest to lowest to all teams participated in the competition.

The ordering of teams is decided by who received the most position-one votes. If two or more teams tie in the first position, we consider the second position to resolve the conflict, if they tie again, we continue this process until the ties are resolved. If two or more teams are still tied after considering all positions, we rank them alphabetically based on their team letter.

Given an array of strings votes which is the votes of all voters in the ranking systems. Sort all teams according to the ranking system described above.

Return a string of all teams sorted by the ranking system.

Example 1:

Input: votes = ["ABC","ACB","ABC","ACB","ACB"]
Output: "ACB"
Explanation: Team A was ranked first place by 5 voters. No other team was voted as first place so team A is the first team.
Team B was ranked second by 2 voters and was ranked third by 3 voters.
Team C was ranked second by 3 voters and was ranked third by 2 voters.
As most of the voters ranked C second, team C is the second team and team B is the third.

Example 2:

Input: votes = ["WXYZ","XYZW"]
Output: "XWYZ"
Explanation: X is the winner due to tie-breaking rule. X has same votes as W for the first position but X has one vote as second position while W doesn't have any votes as second position. 

Example 3:

Input: votes = ["ZMNAGUEDSJYLBOPHRQICWFXTVK"]
Output: "ZMNAGUEDSJYLBOPHRQICWFXTVK"
Explanation: Only one voter so his votes are used for the ranking.

Example 4:

Input: votes = ["BCA","CAB","CBA","ABC","ACB","BAC"]
Output: "ABC"
Explanation: 
Team A was ranked first by 2 voters, second by 2 voters and third by 2 voters.
Team B was ranked first by 2 voters, second by 2 voters and third by 2 voters.
Team C was ranked first by 2 voters, second by 2 voters and third by 2 voters.
There is a tie and we rank teams ascending by their IDs.

Example 5:

Input: votes = ["M","M","M","M"]
Output: "M"
Explanation: Only team M in the competition so it has the first rank.

Constraints:

  • 1 <= votes.length <= 1000
  • 1 <= votes[i].length <= 26
  • votes[i].length == votes[j].length for 0 <= i, j < votes.length.
  • votes[i][j] is an English upper-case letter.
  • All characters of votes[i] are unique.
  • All the characters that occur in votes[0] also occur in votes[j] where 1 <= j < votes.length.

给定很多人对很多team的打分排序列表,如果一个队排在前面的名次越多,则其最终名次越高,据此输出最终排序列表。

规则很复杂,其实很简单。设计一个Team的类,它有一个scores数组,scores[i]表示这个队被多少人投票排在了第i名。由于最多只有26个队,所以scores的维度为26。对Team自定义排序函数,排序规则是依次比较scores的每个元素大小,如果都相等的话,最后比较name的大小。

完整代码如下:

const int MAXN = 26;
class Team {
public:
	char name;
	vector<int> scores;

	Team() :name(0) {
		scores.resize(MAXN, 0);
	};

	bool operator<(const Team& t) {
		for (int i = 0; i < MAXN; ++i) {
			if (scores[i] > t.scores[i]) {
				return true;
			}
			else if (scores[i] < t.scores[i]) {
				return false;
			}
		}
		return name < t.name;
	}
};

class Solution {
public:
	string rankTeams(vector<string>& votes) {
		vector<Team> teams(MAXN, Team());
		for (int j = 0; j < votes[0].size(); ++j) {
			int idx = votes[0][j] - 'A';
			teams[idx].name = votes[0][j]; // 出现的team name
		}
		for (int i = 0; i < votes.size();++i) {
			for (int j = 0; j < votes[i].size(); ++j) {
				int idx = votes[i][j] - 'A';
				++teams[idx].scores[j];
			}
		}
		vector<Team> showups;
		for (int i = 0; i < MAXN; ++i) {
			if (teams[i].name != 0) {
				showups.push_back(teams[i]);
			}
		}
		sort(showups.begin(), showups.end());
		string ans = "";
		for (int i = 0; i < showups.size(); ++i) {
			ans += showups[i].name;
		}
		return ans;
	}
};

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

LeetCode How Many Numbers Are Smaller Than the Current Number

1365. How Many Numbers Are Smaller Than the Current Number

Given the array nums, for each nums[i] find out how many numbers in the array are smaller than it. That is, for each nums[i] you have to count the number of valid j's such that j != i and nums[j] < nums[i].

Return the answer in an array.

Example 1:

Input: nums = [8,1,2,2,3]
Output: [4,0,1,1,3]
Explanation: 
For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and 3). 
For nums[1]=1 does not exist any smaller number than it.
For nums[2]=2 there exist one smaller number than it (1). 
For nums[3]=2 there exist one smaller number than it (1). 
For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).

Example 2:

Input: nums = [6,5,4,8]
Output: [2,1,0,3]

Example 3:

Input: nums = [7,7,7,7]
Output: [0,0,0,0]

Constraints:

  • 2 <= nums.length <= 500
  • 0 <= nums[i] <= 100

给定一个数组,对于数组中的每个元素,计算数组中有多少个数小于这个元素。

简单题。因为数组元素的范围很小,在[0, 100]之间,所以直接用hash计算出每个元素出现的次数,然后算出前n项累加和,即可得出小于当前项的元素个数之和,最后查表即可。

完整代码如下:

class Solution {
public:
	vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
		const int MAXN = 101;
		vector<int> ans(nums.size(), 0);
		vector<int> cnt(MAXN, 0);
		for (int i = 0; i < nums.size(); ++i) {
			++cnt[nums[i]];
		}
		for (int i = 1; i < MAXN; ++i) {
			cnt[i] += cnt[i - 1];
		}
		for (int i = 0; i < nums.size(); ++i) {
			if (nums[i] > 0) {
				ans[i] = cnt[nums[i] - 1];
			}
		}
		return ans;
	}
};

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