1102. Invert a Binary Tree (25)

1.和leetcode中的Invert Binary Tree(easy)题目一样。

2.利用递归函数,每次都把左右子树翻转即可。

翻转函数如下:


void invertTree(TreeNode* root)
{
	if (root != NULL)
	{
		swap(root->l, root->r);
		invertTree(root->l);
		invertTree(root->r);
	}
	
}
时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

The following is from Max Howell @twitter:

Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.

Now it’s your turn to prove that YOU CAN invert a binary tree!

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<=10) which is the total number of nodes in the tree — and hence the nodes are numbered from 0 to N-1. Then N lines follow, each corresponds to a node from 0 to N-1, and gives the indices of the left and right children of the node. If the child does not exist, a “-” will be put at the position. Any pair of children are separated by a space.

Output Specification:

For each test case, print in the first line the level-order, and then in the second line the in-order traversal sequences of the inverted tree. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.

Sample Input:

8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6

Sample Output:

3 7 2 6 4 0 5 1
6 5 7 4 3 2 0 1

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
struct TreeNode{
	int val;
	TreeNode*l, *r;
	TreeNode() :val(-1),l(NULL), r(NULL){};
};
void invertTree(TreeNode* root)
{
	if (root != NULL)
	{
		swap(root->l, root->r);
		invertTree(root->l);
		invertTree(root->r);
	}
	
}
void levelOrder(TreeNode*root,vector<int>&ans)
{
	queue<TreeNode*> q;
	if (root != NULL)
	{
		q.push(root);
		int count1 = 1;
		int count2 = 0;
		while (!q.empty())
		{
			for (int i = 0; i < count1; i++)
			{
				TreeNode* head = q.front(); q.pop();
				ans.push_back(head->val);
				if (head->l != NULL)
				{
					q.push(head->l);
					count2++;
				}
				if (head->r != NULL)
				{
					q.push(head->r);
					count2++;
				}
			}
			count1 = count2;
			count2 = 0;
		}

	}
}
void inOrder(TreeNode*root, vector<int>&ans)
{
	if (root != NULL)
	{
		inOrder(root->l, ans);
		ans.push_back(root->val);
		inOrder(root->r, ans);
	}
}
int main(void)
{
	
	int sum;
	cin >> sum;
	vector<TreeNode> tree(sum);
	vector<int> degree(sum,0);
	for (int i = 0; i < sum; i++)
	{
		tree[i].val = i;
		char a, b;
		cin >> a >> b;
		if (a!='-')
		{
			tree[i].l = &tree[a - '0'];
			degree[a - '0']++;
		}
		if (b != '-')
		{
			tree[i].r = &tree[b - '0'];
			degree[b - '0']++;
		}
	}
	TreeNode* root=NULL;
	for (int i = 0; i < sum; i++)
	{
		if (degree[i] == 0)
		{
			root = &tree[i];
			break;
		}
	}
	invertTree(root);
	vector<int> ans1(0);
	vector<int> ans2(0);
	levelOrder(root, ans1);
	inOrder(root, ans2);
	for (int i = 0; i < ans1.size(); i++)
	{
		cout << ans1[i];
		if (i != ans1.size() - 1)
			cout << " ";
	}
	cout << endl;
	for (int i = 0; i < ans2.size(); i++)
	{
		cout << ans2[i];
		if (i != ans2.size() - 1)
			cout << " ";
	}
	cout << endl;
	return 0;
}

1101. Quick Sort (25)

1.题目要求判断一个数组中,哪些元素可以作为当前数组组合的pivot(可以理解为经过了若干轮的快排后,pivot在最终的位置)。

2.这道题目需要考虑采用适当的数据结构,即小根堆和大根堆

3.判断某个元素是否能够成为pivot,那么该元素左边数组应该构成一个大根堆,堆顶元素应该小于该元素,该元素的右边构成小根堆,堆顶元素大于该元素

4.左边的小根堆,一直插入即可,利用priority_queue,而右边则需要进行维护,需要编写仿函数

5.右边的大根堆维护机制:建立哈希表times,记录每个元素出现的次数,每往后检测新元素数,把新元素出现的次数-1,同时检测大根堆的堆顶元素,如果出现次数为0则弹出,直至剩下出现次数不为0的堆顶。

时间限制
200 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CAO, Peng

There is a classical process named partition in the famous quick sort algorithm. In this process we typically choose one element as the pivot. Then the elements less than the pivot are moved to its left and those larger than the pivot to its right. Given N distinct positive integers after a run of partition, could you tell how many elements could be the selected pivot for this partition?

For example, given N = 5 and the numbers 1, 3, 2, 4, and 5. We have:

  • 1 could be the pivot since there is no element to its left and all the elements to its right are larger than it;
  • 3 must not be the pivot since although all the elements to its left are smaller, the number 2 to its right is less than it as well;
  • 2 must not be the pivot since although all the elements to its right are larger, the number 3 to its left is larger than it as well;
  • and for the similar reason, 4 and 5 could also be the pivot.
    Hence in total there are 3 pivot candidates.

    Input Specification:

    Each input file contains one test case. For each case, the first line gives a positive integer N (<= 105). Then the next line contains N distinct positive integers no larger than 109. The numbers in a line are separated by spaces.

    Output Specification:

    For each test case, output in the first line the number of pivot candidates. Then in the next line print these candidates in increasing order. There must be exactly 1 space between two adjacent numbers, and no extra space at the end of each line.

    Sample Input:

    5
    1 3 2 4 5
    

    Sample Output:

    3
    1 4 5
    

 
AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
struct cmp
{
	bool operator()(const int&a, const int&b)
	{
		return a > b;
	}
};
int main(void)
{
	
	int sum;
	cin >> sum;
	int *num = new int[sum];
	map<int, int> times;
	/*vector<int> times(100001, 0);*/
	priority_queue<int> lq;
	priority_queue<int,vector<int>,cmp> rq;
	for (int i = 0; i < sum; i++)
	{
		scanf("%d", &num[i]);
		times[num[i]]++;
		rq.push(num[i]);
	}
	vector<int> ans(0);
	for (int i = 0; i < sum; i++)
	{
		if (i>0) lq.push(num[i - 1]);
		if (rq.size() != 0)
		{//如果右边heap不为空
			times[num[i]]--;//减少num[i]的次数,以维护右边的小根堆
			while (rq.size() != 0 && times[rq.top()] == 0) rq.pop();//检测堆顶元素,出现次数是否为0,如果为0,证明应该被弹出,
			if (rq.size() != 0 && num[i]>rq.top())
			{
				continue;
			}
		}
		if (lq.size() != 0 && num[i] < lq.top())
		{
			continue;
		}
		ans.push_back(num[i]);
	}
	cout << ans.size() << endl;
	sort(ans.begin(), ans.end());
	for (int i = 0; i < ans.size(); i++)
	{
		printf("%d", ans[i]);
		if (i != ans.size() - 1)
			cout << " ";
	}
	cout << endl;//注意在后面添加换行
	return 0;
}

1100. Mars Numbers (20)

1.题目考察十进制与13进制之间的转换。

2.注意输入为13,26,39整数时,只输出一个marsNum,后面低位的0不输出。

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

People on Mars count their numbers with base 13:

  • Zero on Earth is called “tret” on Mars.
  • The numbers 1 to 12 on Earch is called “jan, feb, mar, apr, may, jun, jly, aug, sep, oct, nov, dec” on Mars, respectively.
  • For the next higher digit, Mars people name the 12 numbers as “tam, hel, maa, huh, tou, kes, hei, elo, syy, lok, mer, jou”, respectively.

For examples, the number 29 on Earth is called “hel mar” on Mars; and “elo nov” on Mars corresponds to 115 on Earth. In order to help communication between people from these two planets, you are supposed to write a program for mutual translation between Earth and Mars number systems.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (< 100). Then N lines follow, each contains a number in [0, 169), given either in the form of an Earth number, or that of Mars.

Output Specification:

For each number, print in a line the corresponding number in the other language.

Sample Input:

4
29
5
elo nov
tam

Sample Output:

hel mar
may
115
13

 
AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
bool isNum(string a)
{
	for (int i = 0; i < a.size(); i++)
	{
		if (a[i]>'9' || a[i] < '0')
			return false;
	}
	return true;
}
int main(void)
{
	vector<string> marsNum = { "tret","jan", "feb", "mar", "apr", "may", "jun", "jly", "aug", "sep", "oct", "nov", "dec" };
	vector<string> marsNum2 = { "tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mer", "jou" };
	map<string, int> mars2Num;
	map<string, int> mars2Num2;
	for (int i = 0; i < marsNum.size(); i++)
	{
		mars2Num[marsNum[i]] = i;
	}
	for (int i = 0; i < marsNum2.size(); i++)
	{
		mars2Num2[marsNum2[i]] = i+1;
	}
	string str = "";
	string n = "";
	getline(cin, n);
	int sum = 0;
	for (int i = 0; i < n.size(); i++)
	{
		sum = sum * 10 + n[i] - '0';
	}
	for (int k = 0; k < sum; k++)
	{
		getline(cin, str);
		if (isNum(str))
		{
			int num = 0;
			for (int i = 0; i < str.size(); i++)
			{
				num = num * 10 + str[i] - '0';
			}
			string ans = "";
			int  low = num % 13;//计算高位和地位
			int  high = num / 13;
			if (high == 0)
				ans = marsNum[low];
			else if (low == 0)//注意输入为13,26,39整数时,只输出一个marsNum,后面低位的0不输出
				ans = marsNum2[high - 1] ;
			else
				ans = marsNum2[high - 1] + " " + marsNum[low];
			cout << ans << endl;
		}
		else
		{
			int ans = 0;
			if (str.size() == 3)
			{
				if (mars2Num.find(str) != mars2Num.end())
				{
					ans = mars2Num[str];
				}
				else
				{//找不到,是在十位上
					ans = mars2Num2[str]*13;
				}
			}
			else
			{
				string high = str.substr(0, 3);
				string low = str.substr(4);
				ans = mars2Num2[high] * 13 + mars2Num[low];
			}
			cout << ans << endl;
		}
	}
	return 0;
}

1099. Build A Binary Search Tree (30)

1.这道题目难度不大,根据给出的数组和BST二叉树,进行填值,主要思想如下:

1)先构建二叉树(此时尚未填值);

2)输出二叉树的中序遍历地址;

3)对数组进行排序;

4)把数组的数输入到中序遍历地址相应的节点值中。

时间限制
100 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
  • Both the left and right subtrees must also be binary search trees.Given the structure of a binary tree and a sequence of distinct integer keys, there is only one way to fill these keys into the tree so that the resulting tree satisfies the definition of a BST. You are supposed to output the level order traversal sequence of that tree. The sample is illustrated by Figure 1 and 2.

    1099
    Input Specification:

    Each input file contains one test case. For each case, the first line gives a positive integer N (<=100) which is the total number of nodes in the tree. The next N lines each contains the left and the right children of a node in the format “left_index right_index”, provided that the nodes are numbered from 0 to N-1, and 0 is always the root. If one child is missing, then -1 will represent the NULL child pointer. Finally N distinct integer keys are given in the last line.

    Output Specification:

    For each test case, print in one line the level order traversal sequence of that tree. All the numbers must be separated by a space, with no extra space at the end of the line.

    Sample Input:

    9
    1 6
    2 3
    -1 -1
    -1 4
    5 -1
    -1 -1
    7 -1
    -1 8
    -1 -1
    73 45 11 58 82 25 67 38 42
    

    Sample Output:

    58 25 82 11 38 67 45 73 42
    

 
AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

struct TreeNode{
	int val;
	TreeNode*left, *right;
	TreeNode(int x) :val(x), left(NULL), right(NULL){};
	TreeNode() :val(-1), left(NULL), right(NULL){};
};
void inOrder(TreeNode*root,vector<TreeNode*>&in)
{
	if (root != NULL)
	{
		inOrder(root->left, in);
		in.push_back(root);
		inOrder(root->right, in);
	}
}
int main(void)
{
	int n;
	cin >> n;
	if (n == 0) return 0;
	TreeNode *tree = new TreeNode[n];
	
	//建立二叉树
	for (int i = 0; i < n; i++)
	{
		int a, b;
		scanf("%d %d", &a, &b);
		if (a != -1)
			tree[i].left = &tree[a];
		if (b != -1)
			tree[i].right = &tree[b];
	}
	//读取数组
	vector<int> num(n, 0);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &num[i]);
	}
	//数组排序
	sort(num.begin(), num.end());

	//建立中序遍历数组
	vector<TreeNode*> treeAddress(0);
	inOrder(&tree[0], treeAddress);
	for (int i = 0; i < n; i++)
	{
		treeAddress[i]->val = num[i];
	}

	//进行层序遍历
	queue<TreeNode*> q;
	int count1 = 0;
	int count2 = 0;
	if (num.size() != 0)
	{
		q.push(&tree[0]);
		count1++;
	}
	vector<int> outPut(0);
	while (!q.empty())
	{
		for (int i = 0; i < count1; i++)
		{
			TreeNode* tmp = q.front(); q.pop();
			outPut.push_back(tmp->val);
			if (tmp->left != NULL)
			{
				q.push(tmp->left);
				count2++;
			}
			if (tmp->right != NULL)
			{
				q.push(tmp->right);
				count2++;
			}
		}
		count1 = count2;
		count2 = 0;
	}

	//输出结果
	for (int i = 0; i < outPut.size(); i++)
	{
		cout << outPut[i];
		if (i != outPut.size() - 1)
			cout << " ";
	}
	cout << endl;

	return 0;
}

1098. Insertion or Heap Sort (25)

1.给出一个初始的排列和一个经过N轮排序的排列,求出是使用插入还是堆排序,并输出下一轮的排列。

2.之前一直开在测试点2里,通过实验知道0、2、4测试点是测插入排序的,1、3、5是堆排的。

3.测试点2卡住,主要是因为插入排序的外层循环我从i=0开始,导致第一步出来的结果和原来的一模一样(i=0,相当于没有进行调整),而把i改为1后,则可以正常AC题目。

4.目前只知道测试点2的情况是,经过若干轮插入排序后,得到的target数组与源数组是一样的,其他细节就无从得知。

5.堆排可以自己写函数,也可以使用make_heap

6.自己写的堆排的程序:

#define LeftChild(i) (2*(i)+1)
void PercDown(vector<int>&num, int i, int n)
{
    int child;
    int tmp;
    for (tmp = num[i]; LeftChild(i) < n; i = child)       {           child = LeftChild(i);           if (child != n - 1 && num[child + 1] > num[child])
             child++;
        if (tmp < num[child])                num[i] = num[child];           else                break;        }  num[i] = tmp;  }  for (int i = n - 1; i>0; i--)
{//进行堆排
     swap(numCopy[0], numCopy[i]);
     PercDown(numCopy, 0, i);
}
时间限制
100 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

According to Wikipedia:

Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. Each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there. It repeats until no input elements remain.

Heap sort divides its input into a sorted and an unsorted region, and it iteratively shrinks the unsorted region by extracting the largest element and moving that to the sorted region. it involves the use of a heap data structure rather than a linear-time search to find the maximum.

Now given the initial sequence of integers, together with a sequence which is a result of several iterations of some sorting method, can you tell which sorting method we are using?

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<=100). Then in the next line, N integers are given as the initial sequence. The last line contains the partially sorted sequence of the N numbers. It is assumed that the target sequence is always ascending. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in the first line either “Insertion Sort” or “Heap Sort” to indicate the method used to obtain the partial result. Then run this method for one more iteration and output in the second line the resuling sequence. It is guaranteed that the answer is unique for each test case. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

Sample Output 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

Sample Input 2:

10
3 1 2 8 7 5 9 4 6 0
6 4 5 1 0 3 2 7 8 9

Sample Output 2:

Heap Sort
5 4 3 1 0 2 6 7 8 9

AC代码,使用make_heap:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

/*
10
6 4 5 1 0 3 2 7 8 9
5 4 2 1 0 3 6 7 8 9
*/
int main(void)
{
	int n;
	cin >> n;
	vector<int> num(n, 0);
	vector<int> num2(n, 0);
	vector<int> numCopy(n, 0);
	vector<int> target(n, 0);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &num[i]);
	}
	numCopy = num;
	num2 = num;
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &target[i]);
	}

	bool isInsert = false;

	for (int i = 1; i < n; i++)
	{//进行插入排序,从i=1,即第二个元素开始插入排序,i=0时,没必要进行插入排序(为什么测试点2会错?)
		int tmp = num[i];
		int j = i;
		for (; j>0 && num[j - 1]>tmp; j--)
		{
			num[j] = num[j - 1];
		}
		num[j] = tmp;
		if (!isInsert && num == target)
		{//是插入排序
			isInsert = true;
		}
		else if (isInsert)
		{
			break;
		}
	}
	if (isInsert)
	{
		cout << "Insertion Sort" << endl;
		for (int i = 0; i < n; i++)
		{
			cout << num[i];
			if (i != n - 1)
				cout << " ";
		}
		cout << endl;
		return 0;
	}

	bool isHeap = false;

	for (int i = n-1; i>=0; i--)
	{//进行堆排,使用原来的函数进行堆排
		make_heap(numCopy.begin(), numCopy.begin() + i+1);
		if (!isHeap && numCopy == target)
		{
			isHeap = true;
		}
		else if (isHeap)
			break;
		swap(numCopy[0], numCopy[i]);//注意是比较了后再交换

	}
	if (isHeap)
	{//如果是堆排,输出并return
		cout << "Heap Sort" << endl;
		for (int i = 0; i < n; i++)
		{
			cout << numCopy[i];
			if (i != n - 1)
				cout << " ";
		}
		cout << endl;
		return 0;
	}
	return 0;
}

AC代码,使用自己写的堆排:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

/*
10
6 4 5 1 0 3 2 7 8 9
5 4 2 1 0 3 6 7 8 9
*/
#define LeftChild(i) (2*(i)+1)
void PercDown(vector<int>&num, int i, int n)
{
	int child;
	int tmp;
	for (tmp = num[i]; LeftChild(i) < n; i = child)
	{
		child = LeftChild(i);
		if (child != n - 1 && num[child + 1] > num[child])
			child++;
		if (tmp < num[child])
			num[i] = num[child];
		else
			break;
	}
	num[i] = tmp;
}

int main(void)
{
	int n;
	cin >> n;
	vector<int> num(n, 0);
	vector<int> num2(n, 0);
	vector<int> numCopy(n, 0);
	vector<int> target(n, 0);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &num[i]);
	}
	numCopy = num;
	num2 = num;
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &target[i]);
	}

	bool isInsert = false;

	for (int i = 1; i < n; i++)
	{//进行插入排序,从i=1,即第二个元素开始插入排序,i=0时,没必要进行插入排序(为什么测试点2会错?)
		int tmp = num[i];
		int j = i;
		for (; j>0 && num[j - 1]>tmp; j--)
		{
			num[j] = num[j - 1];
		}
		num[j] = tmp;
		if (!isInsert && num == target)
		{//是插入排序
			isInsert = true;
		}
		else if (isInsert)
		{
			break;
		}
	}
	if (isInsert)
	{
		cout << "Insertion Sort" << endl;
		for (int i = 0; i < n; i++)
		{
			cout << num[i];
			if (i != n - 1)
				cout << " ";
		}
		cout << endl;
		return 0;
	}
	
	bool isHeap = false;
	for (int i = n / 2; i >= 0; i--)
		PercDown(numCopy, i, n);
	for (int i = n - 1; i>0; i--)
	{//进行堆排
		swap(numCopy[0], numCopy[i]);
		PercDown(numCopy, 0, i);
		if (!isHeap && numCopy == target)
		{
			isHeap = true;
		}
		else if (isHeap)
			break;
		//cout << "Heap Sort" << endl;
		//for (int i = 0; i < n; i++)
		//{
		//	cout << numCopy[i];
		//	if (i != n - 1)
		//		cout << " ";
		//}

	}
	if (isHeap)
	{//如果是堆排,输出并return
		cout << "Heap Sort" << endl;
		for (int i = 0; i < n; i++)
		{
			cout << numCopy[i];
			if (i != n - 1)
				cout << " ";
		}
		cout << endl;
		return 0;
	}
	return 0;
}

1097. Deduplication on a Linked List (25)

1.题目要求删除重复的节点,并把重复的节点建立成一个新的链表,最终输出两个链表,一个是去重的链表,一个是重复节点组成的链表。

2.主要是考察链表的删除和建表操作,使用map进行记录已经存在过的链表节点。

3.注意是删除绝对值相同的节点。

1097

时间限制
300 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Given a singly linked list L with integer keys, you are supposed to remove the nodes with duplicated absolute values of the keys. That is, for each value K, only the first node of which the value or absolute value of its key equals K will be kept. At the mean time, all the removed nodes must be kept in a separate list. For example, given L being 21→-15→-15→-7→15, you must output 21→-15→-7, and the removed list -15→15.

Input Specification:

Each input file contains one test case. For each case, the first line contains the address of the first node, and a positive N (<= 105) which is the total number of nodes. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.

Then N lines follow, each describes a node in the format:

Address Key Next

where Address is the position of the node, Key is an integer of which absolute value is no more than 104, and Next is the position of the next node.

Output Specification:

For each case, output the resulting linked list first, then the removed list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:

00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854

Sample Output:

00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
/*
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854

00001 2
00002 1 -1
00001 1 00002

*/
struct ListNode{
	int val, add;
	ListNode* next;
	ListNode() :val(-1), add(-1), next(NULL){};
	ListNode(int x,int a) :val(x), add(a), next(NULL){};
};
int main(void)
{
	ListNode *list = new ListNode[100000];
	map<int, bool> exist;
	int headAdd, n;
	cin >> headAdd >> n;
	for (int i = 0; i < n; i++)
	{
		int pre, val, next;
		scanf("%d %d %d", &pre, &val, &next);
		list[pre].val = val;
		list[pre].add = pre;
		if (next != -1)
		{
			list[next].add = next;
			list[pre].next = &list[next];
		}
		else
			list[pre].next = NULL;
	}

	ListNode*head = &list[headAdd];
	ListNode*preHead = head;
	ListNode*newList = new ListNode(-1, -1);
	ListNode*newListHead = newList;
	while (head != NULL)
	{
		if (exist[abs(head->val)])
		{
			preHead->next = head->next;
			newList->next = head;//
			newList = newList->next;//newList现在指向head
			head = preHead->next;
			newList->next = NULL;
		}
		else
		{
			exist[abs(head->val)] = true;
			preHead = head;
			head = head->next;
		}
	}

	head = &list[headAdd];
	while (head != NULL)
	{
		printf("%05d %d ", head->add, head->val);
		if (head->next != NULL)
			printf("%05d\n", head->next->add);
		else
			printf("-1\n");
		head = head->next;
	}
	head = newListHead->next;
	while (head != NULL)
	{
		printf("%05d %d ", head->add, head->val);
		if (head->next != NULL)
			printf("%05d\n", head->next->add);
		else
			printf("-1\n");
		head = head->next;
	}

	return 0;
}

1096. Consecutive Factors (20)

1.题目要求求连续的质因数。

2.最开始卡在最后一个测试点中,后来经过对偶数情况的优化,发现仍然超时,于是考虑是奇数情况下超时,实际上,最后一个测试例子应该是一个非常大的质数

3.把情况分为奇数和偶数,

1)奇数情况下,答案肯定为1个,遇到第一个整除的数,则直接输出;

但是采用遍历至n时,最后一个测试例子会超时,于是采用质因数分解的算法:

质因数分解算法如下:

情况一:当n是素数时,n的质因素要么是n本身;
情况二:在除去最大质因素的情况下,一定小于等于sqrt(n),如2*17=34,sqrt(34)=5,除去最大质因素17,剩下的质因素小于5 ;

于是,把时间复杂度降为o(sqrt(n)),最终一个例子通过

2)偶数情况下,当n小于6时,只有1个,但是当n大于6时,肯定有两个以上的连续因数,必然包含2*3;

于是我采用了计算各种情况下连续因数相乘时,因数的最大值是多少(即小于INT_MAX),答案如下:


<strong>//下面是质因素数组,虽然最后没有对AC提供帮助,但是可以优化时间复杂度
//偶数情况下,除了2,其他情况下至少有两个连续的因数,2*3
//当已经有2个因数后,接下来只需要求3个因数的情况,在连续3个因数的情况下,满足要求的最大值是1287*1288*1289,所以取边界值1290
//当已经有3个连续因素后,接下来只需要求4个因数的情况,在连续4个因素的情况下,满足要求的最大值是211*212*213*214,所以取边界值215
//其他同理
vector<int> maxFactor = { INT_MAX, n, (int)((double)sqrt(n) + 1), 1290, 215, 73, 35, 21, 14, 10, 0 };//3~13</strong>

3)由这道题目想到的其他问题:

连续两个数相乘,肯定可以被2整除,因为连续的两个数,必然包含偶数

连续三个数相乘,肯定可以被6整除(lcm(2,3)),因为连续的三个数,必然覆盖3的倍数和2的倍数

连续四个数相乘,肯定可以被12整除(lcm(2,3,4)),连续的三个数,必然覆盖2,3,4的倍数

连续若干个数都符合上述特征。

1096

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Among all the factors of a positive integer N, there may exist several consecutive numbers. For example, 630 can be factored as 3*5*6*7, where 5, 6, and 7 are the three consecutive numbers. Now given any positive N, you are supposed to find the maximum number of consecutive factors, and list the smallest sequence of the consecutive factors.

Input Specification:

Each input file contains one test case, which gives the integer N (1<N<231).

Output Specification:

For each test case, print in the first line the maximum number of consecutive factors. Then in the second line, print the smallest sequence of the consecutive factors in the format “factor[1]*factor[2]*…*factor[k]”, where the factors are listed in increasing order, and 1 is NOT included.

Sample Input:

630

Sample Output:

3
5*6*7

 
AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
//2147483646
void dfsFactor(long long n, long long preNum, vector<int>&factor, vector<vector<int>>&ans,int&factorSize)
{
	if (n % (preNum + 1) == 0)
	{//因数连续,继续DFS
		factor.push_back(preNum + 1);
		dfsFactor(n / (preNum + 1), preNum + 1, factor, ans, factorSize);
	}
	else if (!factor.empty() && factor.size() > factorSize)
	{//不连续时,如果连续因数的数量大于上次最大值,则压入答案中
		factorSize = factor.size();
		ans.push_back(factor);
	}
}
bool cmp(const vector<int>&a, const vector<int>&b)
{
	if (a.size() > b.size())
		return true;
	else if (a.size() == b.size() && a[0] < b[0])
		return true;
	else return false;
}
int main(void)
{
	//分为奇数和偶数情况,奇数情况,肯定不能被6整除,最多只有一个因素,因此分情况处理
	int n;
	cin >> n;
		if (n % 2 == 1)
		{//奇数情况下,采用质因素分解的算法
			/*
			情况一:当n是素数时,n的质因素要么是n本身
			情况二:在除去最大质因素的情况下,一定小于等于sqrt(n),如2*17=34,sqrt(34)=5,除去最大质因素17,剩下的质因素小于5 
			*/
			int temp = (int)((double)sqrt(n) + 1);
			for (int i = 2; i <= temp; ++i)
			{
				if (n%i == 0)
				{
					cout << "1" << endl;
					cout << i << endl;
					return 0;//直接返回
				}
			}
			cout << "1" << endl;
			cout << n << endl;

		}
		else
		{
			//下面是质因素数组,虽然最后没有对AC提供帮助,但是可以优化时间复杂度
			//偶数情况下,除了2,其他情况下至少有两个连续的因数,2*3
			//当已经有2个因数后,接下来只需要求3个因数的情况,在连续3个因数的情况下,满足要求的最大值是1287*1288*1289,所以取边界值1290
			//当已经有3个连续因素后,接下来只需要求4个因数的情况,在连续4个因素的情况下,满足要求的最大值是211*212*213*214,所以取边界值215
			//其他同理
			vector<int> maxFactor = { INT_MAX, n, (int)((double)sqrt(n) + 1), 1290, 215, 73, 35, 21, 14, 10, 0 };//3~13
			vector<int> factor(0);
			vector<vector<int>>ans(0);
			int factorSize = 0;

			for (long long i = 1; i <= min(n, maxFactor[factorSize + 1]); i++)
			{
				if (n % (i + 1) == 0)
				{
					dfsFactor(n, i, factor, ans, factorSize);
					factor.clear();
				}
			}
			sort(ans.begin(), ans.end(), cmp);
			cout << ans[0].size() << endl;
			for (int i = 0; i < ans[0].size(); i++)
			{
				cout << ans[0][i];
				if (i != ans[0].size() - 1)
					cout << "*";
			}
			cout << endl;
		}
	return 0;
}

1095. Cars on Campus (30)

1.事件模拟。

2.首先读取所有的汽车记录数据,筛选出合理的进入和离开时间,放到一个vector里面,对这个vector进行排序处理,进入时间早的放在前面。

3.对每一秒进行模拟,已经进入的车辆用一个小根堆进行存储维护,离开时间早的,排在堆顶。

3.取下一次进入校园车辆的时间,下一次离开校园车辆的时间,下一次查询的时间,取三者的最小值,直接跳那个时间点,进行处理,优化时间复杂度。

4.一开始第4个例子超时,后来采用了第3点中提到的优化方法,结果还是超时,考虑到查询量较大,于是把查询的cout改为printf,就通过了。

Each input file contains one test case. Each case starts with two positive integers N (<= 10000), the number of records, and K (<= 80000) the number of queries. Then N lines follow, each gives a record in the format。

1)最原始的一秒一秒进行模拟:1095-1

2)采用第3点的方法进行优化,还是超时

1095-2

3)不进行时间事件模拟处理,仅输入数据,各测试点耗费时间:

1095-3

4)最后把cout改为printf,通过:

1095-4

时间限制
220 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Zhejiang University has 6 campuses and a lot of gates. From each gate we can collect the in/out times and the plate numbers of the cars crossing the gate. Now with all the information available, you are supposed to tell, at any specific time point, the number of cars parking on campus, and at the end of the day find the cars that have parked for the longest time period.

Input Specification:

Each input file contains one test case. Each case starts with two positive integers N (<= 10000), the number of records, and K (<= 80000) the number of queries. Then N lines follow, each gives a record in the format

plate_number hh:mm:ss status

where plate_number is a string of 7 English capital letters or 1-digit numbers; hh:mm:ss represents the time point in a day by hour:minute:second, with the earliest time being 00:00:00 and the latest 23:59:59; and status is either in or out.

Note that all times will be within a single day. Each “in” record is paired with the chronologically next record for the same car provided it is an “out” record. Any “in” records that are not paired with an “out” record are ignored, as are “out” records not paired with an “in” record. It is guaranteed that at least one car is well paired in the input, and no car is both “in” and “out” at the same moment. Times are recorded using a 24-hour clock.

Then K lines of queries follow, each gives a time point in the format hh:mm:ss. Note: the queries are given in ascending order of the times.

Output Specification:

For each query, output in a line the total number of cars parking on campus. The last line of output is supposed to give the plate number of the car that has parked for the longest time period, and the corresponding time length. If such a car is not unique, then output all of their plate numbers in a line in alphabetical order, separated by a space.

Sample Input:

16 7
JH007BD 18:00:01 in
ZD00001 11:30:08 out
DB8888A 13:00:00 out
ZA3Q625 23:59:50 out
ZA133CH 10:23:00 in
ZD00001 04:09:59 in
JH007BD 05:09:59 in
ZA3Q625 11:42:01 out
JH007BD 05:10:33 in
ZA3Q625 06:30:50 in
JH007BD 12:23:42 out
ZA3Q625 23:55:00 in
JH007BD 12:24:23 out
ZA133CH 17:11:22 out
JH007BD 18:07:01 out
DB8888A 06:30:50 in
05:10:00
06:30:50
11:00:00
12:23:42
14:00:00
18:00:00
23:59:00

Sample Output:

1
4
5
2
1
0
1
JH007BD ZD00001 07:20:09

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

struct CarNode{
	vector<pair<string, bool>> record;
	vector<pair<string, string>> validRecord;
	CarNode() :record(0), validRecord(0){};
};
struct RecordNode{

	string id, in, out;
	RecordNode() :id(""), in(""), out(""){};
	RecordNode(string i,string a,string b) :id(i), in(a), out(b){};

};
bool cmpRecord(const pair<string, bool>&a, const pair<string, bool>&b)
{
	return a.first < b.first;
}
bool cmpAllRecord(const RecordNode&a, const RecordNode&b)
{
	return a.in < b.in;
}
int char2int(char a)
{
	return a - '0';
}
int time2sec(string str)
{
	return (char2int(str[0]) * 10 + char2int(str[1])) * 60*60 + (char2int(str[3]) * 10 + char2int(str[4])) * 60 + char2int(str[6]) * 10 + char2int(str[7]);
}
struct cmp
{
	bool operator()(const RecordNode&a, const RecordNode&b)
	{
		return time2sec(a.out) > time2sec(b.out);
	}
};
bool cmpPark(const pair<string, int>&a, const pair<string, int>&b)
{
	if (a.second > b.second) return true;
	else if (a.second == b.second&&a.first < b.first) return true;
	else return false;
}
string sec2str(int a)
{
	int hour = a / 3600;
	int min = (a - hour * 3600) / 60;
	int sec = a - hour * 3600 - min * 60;

	char c1 = hour / 10 + '0';
	char c2 = hour % 10 + '0';
	string ans = "";
	ans += c1;
	ans += c2;
	ans += ":";
	c1 = min / 10 + '0';
	c2 = min % 10 + '0';
	ans += c1;
	ans += c2;
	ans += ":";
	c1 = sec / 10 + '0';
	c2 = sec % 10 + '0';
	ans += c1;
	ans += c2;
	return ans;

}
int main(void)
{
	int recordSum,querySum;
	cin >> recordSum >> querySum;

	map<string, CarNode> car;//建立car 哈希表
	for (int i = 0; i < recordSum; i++)
	{//输入记录
		string id, time, flag;
		cin >> id >> time >> flag;
		//0为进入,1为出去
		if (flag == "in")
			car[id].record.push_back({ time, 0 });
		else
			car[id].record.push_back({ time, 1 });
	}
	vector<RecordNode> allRecord(0);
	for (map<string, CarNode>::iterator ite = car.begin(); ite != car.end(); ite++)
	{//筛选出有效记录,统一发到allRecord容器中
		sort(ite->second.record.begin(), ite->second.record.end(), cmpRecord);
		for (int i = 0; i < ite->second.record.size() - 1; i++)
		{
			if (!ite->second.record[i].second && ite->second.record[i + 1].second)
			{//相邻的两条记录,第一条为进入,第二条为离开,则合理
				allRecord.push_back(RecordNode(ite->first, ite->second.record[i].first, ite->second.record[i + 1].first));
			}
		}
	}
	//根据进入时间,对有效记录进行排序
	sort(allRecord.begin(), allRecord.end(), cmpAllRecord);
	
	//输入查询记录
	vector<string> queryRecord(querySum);
	for (int i = 0; i < querySum; i++)
	{
		cin >> queryRecord[i];
	}
	sort(queryRecord.begin(), queryRecord.end());

	int parkCar = 0;
	int next = 0;
	int queryIdx = 0;
	map<string, int> parkTime;

	//优先队列,记录了在校园内的车,以离开时间大小建立小根堆
	priority_queue<RecordNode, vector<RecordNode>, cmp> inCampus;
	int maxTime = 0;
	string maxID = "";
	vector<pair<string, int>> maxTimeCar(0);
	for (int i = 0; i < 24 * 3600; i++)
	{
		while (next<allRecord.size() && time2sec(allRecord[next].in) == i)
		{//查看当前是否有车进入校园
			inCampus.push(allRecord[next]);
			next++;
			parkCar++;
		}
		while (!inCampus.empty() && time2sec(inCampus.top().out) == i)
		{//查看当前是否有车离开校园
			//记录停车时间
			parkTime[inCampus.top().id] += time2sec(inCampus.top().out) - time2sec(inCampus.top().in);

			if (parkTime[inCampus.top().id] >= maxTime)
			{
				maxTimeCar.push_back({ inCampus.top().id, parkTime[inCampus.top().id] });
				maxTime = parkTime[inCampus.top().id];
				maxID = inCampus.top().id;
			}

			inCampus.pop();
			parkCar--;
		}
		if (queryIdx<queryRecord.size() && time2sec(queryRecord[queryIdx]) == i)
		{
			queryIdx++;
			printf("%d\n",parkCar);//刚开始采用了cout输出,结果超时,改为printf后不超时
		}
		int inTime = 24 * 3600, outTime = 24 * 3600, queryTime = 24 * 3600;
		if (next < allRecord.size())//记录下一个需要处理的时间点
			inTime = time2sec(allRecord[next].in);
		if (!inCampus.empty())//记录下一个需要处理的时间点
			outTime = time2sec(inCampus.top().out);
		if (queryIdx < queryRecord.size())//记录下一个需要处理的时间点
			queryTime = time2sec(queryRecord[queryIdx]);

		int nextTime = min(min(inTime,outTime),queryTime);
		i = nextTime - 1;//因为for循环里面有i++,所以这里不需要直接达到nextTime

	}
	//对最大停车的车辆数组进行排序
	sort(maxTimeCar.begin(), maxTimeCar.end(), cmpPark);
	for (int i = 0; i < maxTimeCar.size(); i++)
	{
		if (maxTimeCar[i].second == maxTime)
		{//停车时间等于最大值,则输出
			cout << maxTimeCar[i].first << " ";//输出ID
		}
		else//不等,则直接跳出循环
			break;
	}
	cout << sec2str(maxTime) << endl;
	return 0;
}

1094. The Largest Generation (25)

1.这道题目主要是求家族树中,哪一层的成员数最多,输出成员数和该层层数。

2.主要考察了层次遍历和数据结构的设计。

时间限制
200 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

A family hierarchy is usually presented by a pedigree tree where all the nodes on the same level belong to the same generation. Your task is to find the generation with the largest population.

Input Specification:

Each input file contains one test case. Each case starts with two positive integers N (<100) which is the total number of family members in the tree (and hence assume that all the members are numbered from 01 to N), and M (<N) which is the number of family members who have children. Then M lines follow, each contains the information of a family member in the following format:

ID K ID[1] ID[2] … ID[K]

where ID is a two-digit number representing a family member, K (>0) is the number of his/her children, followed by a sequence of two-digit ID’s of his/her children. For the sake of simplicity, let us fix the root ID to be 01. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in one line the largest population number and the level of the corresponding generation. It is assumed that such a generation is unique, and the root level is defined to be 1.

Sample Input:

23 13
21 1 23
01 4 03 02 04 05
03 3 06 07 08
06 2 12 13
13 1 21
08 2 15 16
02 2 09 10
11 2 19 20
17 1 22
05 1 11
07 1 14
09 1 17
10 1 18

Sample Output:

9 4

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

struct Node{
	vector<int> list;
	Node() :list(0){};
};
int main(void)
{
	int totalNum, recordNum;
	cin >> totalNum >> recordNum;
	vector<Node> tree(totalNum+1);
	for (int i = 0; i < recordNum; i++)
	{
		int id, n;
		cin >> id >> n;
		for (int j = 0; j < n; j++)
		{
			int tmp;
			cin >> tmp;
			tree[id].list.push_back(tmp);
		}
	}

	queue<int> q;
	q.push(1);
	int count1 = 1;
	int count2 = 0;
	int maxFamilyMember = 1, maxFamilyLevel = 1;
	int level = 1;
	while (!q.empty())
	{
		for (int i = 0; i < count1; i++)
		{
			int root = q.front(); q.pop();
			for (int j = 0; j < tree[root].list.size(); j++)
			{
				q.push(tree[root].list[j]);
			}
			count2 += tree[root].list.size();
		}
		level++;
		if (count2 > maxFamilyMember)
		{
			maxFamilyMember = count2;
			maxFamilyLevel = level;
		}
		count1 = count2;
		count2 = 0;
	}
	cout << maxFamilyMember << " " << maxFamilyLevel << endl;



	return 0;
}

1093. Count PAT’s (25)

1.求出给定字符串中,PAT的组合数。

2.这道题目比较有趣,我的思路如下:

1)首先统计countP[i],即0~i的位置上,一共有多少个P,同理可以反向统计出countT[i],即i到n-1之间有多少个T。

2)遍历string,当str[i]==‘A’时,那么ans+=countP[i-1]*countT[i+1],当然, 需要根据题目要求,对100000007取模。

1093

时间限制
120 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CAO, Peng

The string APPAPT contains two PAT‘s as substrings. The first one is formed by the 2nd, the 4th, and the 6th characters, and the second one is formed by the 3rd, the 4th, and the 6th characters.

Now given any string, you are supposed to tell the number of PAT‘s contained in the string.

Input Specification:

Each input file contains one test case. For each case, there is only one line giving a string of no more than 105characters containing only P, A, or T.

Output Specification:

For each test case, print in one line the number of PAT‘s contained in the string. Since the result may be a huge number, you only have to output the result moded by 1000000007.

Sample Input:

APPAPT

Sample Output:

2

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

#define maxDivide 1000000007
int main(void)
{
	string str;
	cin >> str;
	int *countP = new int[str.size()];
	int *countT = new int[str.size()];
	memset(countP, 0, sizeof(countP));
	memset(countT, 0, sizeof(countT));
	if (str[0] == 'P') countP[0] = 1;
	if (str[str.size() - 1] == 'T') countT[str.size() - 1] = 1;
	for (int i = 1; i < str.size(); i++)
	{
		if (str[i] == 'P')
			countP[i] = countP[i - 1] + 1;
		else
			countP[i] = countP[i - 1];
	}

	for (int i = str.size()-2; i >=0; i--)
	{
		if (str[i] == 'T')
			countT[i] = countT[i + 1] + 1;
		else
			countT[i] = countT[i + 1];
	}
	unsigned long long ans = 0;
	for (int i = 1; i < str.size() - 1; i++)
	{
		if (str[i] == 'A')
		{
			unsigned long long tmp = (countP[i - 1] * countT[i + 1]) % maxDivide;
			ans += tmp;
			ans = ans%maxDivide;
		}
	}

	cout << ans << endl;

	return 0;
}