mituh's notes


  • 首页

  • 归档

1009 Product of Polynomials(25) - PAT甲级

发表于 2018-09-04

1009 Product of Polynomials(25)

This time, you are supposed to find A×B where A and B are two polynomials.

Input Specification:

Each input file contains one test case. Each case occupies 2 lines, and each line contains the information of a polynomial:

where K is the number of nonzero terms in the polynomial, N​i and aNi(i=1,2,⋯,K) are the exponents and coefficients, respectively. It is given that 1≤K≤10, 0≤NK<⋯<N2<N1≤1000.

Output Specification:

For each test case you should output the product of A and B in one line, with the same format as the input. Notice that there must be NO extra space at the end of each line. Please be accurate up to 1 decimal place.

Sample Input:

2 1 2.4 0 3.2
2 2 1.5 1 0.5

Sample Output:

3 3 3.6 2 6.0 1 1.6

Solution:

Polynomials是多项式的意思.
每个case给出两行,

2 1 2.4 0 3.2     // 2.4*X^1 + 3.2*X^0
2 2 1.5 1 0.5 // 1.5*X^2 + 0.5*X^1

A*B的结果就是

3 3 3.6 2 6.0 1 1.6    // 3.6*X^3 + 6.0*X^2 + 1.6*X^1

总的相乘的结果是, 对应项相乘后相加的结果。
对应项相乘, 指数相加, 系数相乘; 如果相乘后的指数已经存在, 该指数对应的总系数要加上这次相乘的系数.

将A和B放在两个map里, 多对多的去相乘。

第一个问题:
相乘后的结果以何种形式保存?

  • 如果放在map中, 可能不满足从指数从大到小排列的顺序, 只能通过一个case.
  • 于是, 用map+vector, 建立一个Node保存计算后的指数n和系数a, 再把node放进vector中排序.

坑点:
若系数a为0的情况, 应该不会被打印。主要a的类型是double, 比较db与0之间的关系。否则会导致case1通不过.s

if ( -0.00005 <= db - 0.0 && db-0.0 <= 0.000005) {    // db == 0
// ..
}

if (db - 0.0 < -0.00005 || db-0.0 > 0.000005) { // db != 0
// ..
}

实际代码如下:

#include <cstdio>
#include <unordered_map>
#include <vector>
#include <algorithm>
using namespace std;

struct Node {
int n;
double a;
};

bool cmp(Node n1, Node n2) {
return n1.n > n2.n;
}

int main() {
unordered_map<int, double> poly1, poly2, ans;
vector<Node> v;
int N, M;
scanf("%d", &N);
for (int i = 0; i < N; i++) {
int n; double a; scanf("%d %lf", &n, &a);
auto it = poly1.find(n);
if (it != poly1.end()) {
it->second += a;
} else {
poly1[n] = a;
}
}
scanf("%d", &M);
for (int i = 0; i < M; i++) {
int n; double a; scanf("%d %lf", &n, &a);
auto it = poly2.find(n);
if (it != poly2.end()) {
it->second += a;
} else {
poly2[n] = a;
}
}

for (auto it1 = poly1.begin(); it1 != poly1.end(); it1++) {
for (auto it2 = poly2.begin(); it2 != poly2.end(); it2++) {
int n = it1->first + it2->first;
double a = it1->second * it2->second;
auto it_ans = ans.find(n);
if (it_ans != ans.end()) {
it_ans->second += a;
} else {
ans[n] = a;
}
}
}
for (auto it = ans.begin(); it != ans.end(); it++) {
if (it->second-0.0 < -0.0005 || it->second-0.0 > 0.0005) { // case1
v.push_back(Node{it->first, it->second});
}
}
sort(v.begin(), v.end(), cmp);
printf("%lu", v.size());
for (int i = 0; i < v.size(); i++) {
printf(" %d %.1lf", v[i].n, v[i].a);
}
return 0;
}

1008 Elevator(20) - PAT甲级

发表于 2018-09-04

1008 Elevator(20)

The highest building in our city has only one elevator. A request list is made up with N positive numbers. The numbers denote at which floors the elevator will stop, in specified order. It costs 6 seconds to move the elevator up one floor, and 4 seconds to move down one floor. The elevator will stay for 5 seconds at each stop.

For a given request list, you are to compute the total time spent to fulfill the requests on the list. The elevator is on the 0th floor at the beginning and does not have to return to the ground floor when the requests are fulfilled.

Input Specification:

Each input file contains one test case. Each case contains a positive integer N, followed by N positive numbers. All the numbers in the input are less than 100.

Output Specification:

For each test case, print the total time on a single line.

Sample Input:

3 2 3 1

Sample Output:

41

Solution:

上升一层6s, 下降4s, 一共有n层, 就+5*n;

#include <cstdio>

int main() {
int N; scanf("%d", &N);
int floor = 0, time = 0;
for (int i = 0; i < N; i++) {
int t; scanf("%d", &t);
time += (t > floor) ? (t-floor)*6 : (floor-t)*4;
floor = t;
}
time += N * 5;
printf("%d", time);
return 0;
}

1006 Sign In and Sign Out(25) - PAT甲级

发表于 2018-09-04

1006 Sign In and Sign Out(25)

At the beginning of every day, the first person who signs in the computer room will unlock the door, and the last one who signs out will lock the door. Given the records of signing in’s and out’s, you are supposed to find the ones who have unlocked and locked the door on that day.

Input Specification:

Each input file contains one test case. Each case contains the records for one day. The case starts with a positive integer M, which is the total number of records, followed by M lines, each in the format:

ID_number Sign_in_time Sign_out_time

where times are given in the format HH:MM:SS, and ID_number is a string with no more than 15 characters.

Output Specification:

For each test case, output in one line the ID numbers of the persons who have unlocked and locked the door on that day. The two ID numbers must be separated by one space.

Note:

It is guaranteed that the records are consistent. That is, the sign in time must be earlier than the sign out time for each person, and there are no two persons sign in or out at the same moment.

Sample Input:

3
CS301111 15:30:28 17:00:10
SC3021234 08:00:00 11:25:25
CS301133 21:45:00 21:58:40

Sample Output:

SC3021234 CS301133

Solution:

时间可以存成字符数组, 用strcmp进行比较, strcmp(time1, time2) < 0, time1比time2早。
只要进行一次升序和一次降序, 就可以得出最早和最晚的时间, 对应的id, 因此存在一个struct中.

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

struct Node {
char id[20];
char in_time[15];
char out_time[15];
};

bool cmp1(Node n1, Node n2) {
return strcmp(n1.in_time, n2.in_time) < 0;
}

bool cmp2(Node n1, Node n2) {
return strcmp(n1.out_time, n2.out_time) > 0;
}

vector<Node> v;

int main() {
int M; scanf("%d", &M);
for (int i = 0; i < M; i++) {
Node n;
scanf("%s %s %s", n.id, n.in_time, n.out_time);
v.push_back(n);
}
sort(v.begin(), v.end(), cmp1);
printf("%s ", v[0].id);
sort(v.begin(), v.end(), cmp2);
printf("%s", v[0].id);
return 0;
}

1005 Spell It Right(20) - PAT甲级

发表于 2018-09-03

1005 Spell It Right(20)

Given a non-negative integer N, your task is to compute the sum of all the digits of N, and output every digit of the sum in English.

Input Specification:

Each input file contains one test case. Each case occupies one line which contains an N (≤10
​100
​​ ).

Output Specification:

For each test case, output in one line the digits of the sum in English words. There must be one space between two consecutive words, but no extra space at the end of a line.

Sample Input:

12345

Sample Output:

one five

Solution:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;

char num[200];
int main() {
string dict[10] = {"zero", "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine"};
scanf("%s", num);
int sum = 0;
for (int i = 0; i < strlen(num); i++) {
sum += num[i]-'0';
}
string s = to_string(sum); int flag = 0;
for (char ch : s) {
if (flag) cout << " ";
cout << dict[ch - '0'];
flag = 1;
}
return 0;
}

206. Reverse Linked List - LeetCode

发表于 2018-09-03

206. Reverse Linked List

Reverse a singly linked list.

Example:

Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL

Follow up:

A linked list can be reversed either iteratively or recursively. Could you implement both?

Solution1:

pNext用于移动pNode, pPrev和找到新的链表头, 保存pPrev用于创建新的链接.

三个变量: 新的链表头reverseHead, 游标结点pNode, 前序结点pPrev,
四个操作: 循环内部创建下一结点, 改变游标指向前序结点, 前序结点移动到游标结点, 游标结点移动到下一结点.
两个判断: 游标结点非空指针时, 进行循环操作; 游标的下一结点为空指针时, 记录新的链表头

// basic reverse
// Time:O(n), Space:O(1)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* reverseHead = nullptr;
ListNode* pNode = head;
ListNode* pPrev = nullptr;
while (pNode != nullptr) {
ListNode* pNext = pNode->next;
if (pNext == nullptr) {
reverseHead = pNode;
}
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return reverseHead;
}

};

Solution2:

1->2->3->4->5;

当5作为头结点指向4的时, 4仍旧指向5, 可以通过每次保留上一次处理的结点, 从末尾前指向

几个注意点:

1, 主要在中间过程中, 找出反转后的头结点;
2, 在反转结束后, 尾指针指向nullptr;
3, 要注意空链表的情况;

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/

// Time:O(n^2), Space:O(1)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == nullptr) return head;
ListNode *pNode = nullptr, *reverseHead = nullptr;
while (pNode != head) {
ListNode *p = head;
while (p->next != pNode) {
p = p->next;
}

if (pNode != nullptr) {
pNode->next = p;
} else {
reverseHead = p;
}
pNode = p;
}
pNode->next = nullptr;
return reverseHead;
}
};

Solution: Follow up1

从随意位置反转链表, 在该位置后的结点不变。
需要保存一个新的头结点, reverseHead; 以及另一结点, nextNode用于, 反转之后的结点拼接。

// follow up1: iteratively
class Solution {
public:
ListNode* reverseList(ListNode* head, int k) {
if (head == nullptr) return head;
ListNode *pNode = head;
for (int i = 0; i < k-1; i++) {
if (pNode->next == nullptr) return head;
pNode = pNode->next;
}
ListNode *reverseHead = pNode, *nextNode = pNode->next;
while (pNode != head) {
ListNode *p = head;
while (p->next != pNode) {
p = p->next;
}
pNode->next = p;
pNode = p;
}
pNode->next = nextNode;
return reverseHead;
}
};

一个测试Sample

input:
[1, 2, 3, 4, 5]
int k = 2;

output:
[2, 1, 3, 4, 5]

Solution: Follow up2

反转呈现周期性, 但是若不满这个周期, 不会反转链表.

// follow up2: recursively
class Solution {
public:
ListNode* reverseList(ListNode* head, int k) {
if (head == nullptr || k <= 1) return head;

ListNode *pNode = head, *reverseHead = nullptr,
*lastHead = head, *lastTail = nullptr;
for (;;) {
for (int i = 0; i < k-1; i++) {
if (pNode->next == nullptr) return reverseHead;
pNode = pNode->next;
}
ListNode *segHead = pNode, *nextNode = pNode->next;
if (reverseHead == nullptr) {
reverseHead = segHead;
}
if (lastTail != nullptr) {
lastTail->next = segHead;
}

while (pNode != lastHead) {
ListNode *p = lastHead;
while (p->next != pNode) {
p = p->next;
}
pNode->next = p;
pNode = p;
}
pNode->next = nextNode;
lastTail = lastHead;
lastHead = nextNode;
pNode = nextNode;
if (lastHead == nullptr) {
return reverseHead;
}
}
return reverseHead;
}
};

测试Sample:

/*
input:
[1,2,3,4,5,6,7,8]
3

[3, 2, 1, 6, 5, 4, 7, 8]


input:
[1,2,3,4,5,6,7,8]
2

[2, 1, 4, 3, 6, 5, 8, 7]
*/

19. Remove Nth Node From End of List - LeetCode

发表于 2018-09-03

19. Remove Nth Node From End of List

Given a linked list, remove the n-th node from the end of list and return its head.

Example:

Given linked list: 1->2->3->4->5, and n = 2.

After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Follow up:

Could you do this in one pass?

Solution1:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/

// two-pass, 扫描两遍, 保存前一个结点的方法
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if (head == nullptr) return head;
ListNode* prev = head, *p = prev->next;
int size = 1;
while (p) {
prev = prev->next;
p = prev->next;
size++;
}

prev = head; p = prev->next;
for (int i = 0; i < size-n-1; i++) {
prev = prev->next;
p = prev->next;
}

if (prev && !p) {
prev = nullptr;
delete(prev); delete(p);
head = nullptr;
} else {
if (prev == head && size-n == 0) {
delete(prev);
head = p;
} else {
prev->next = p->next;
delete(p);
}
}
return head;
}
};

Solution2:

一个node先在原地等待, 当p到达n=1的位置时候, cur和p一起移动, 当p移动到最后一个结点时, cur就是要删除的结点。

// one-pass, 更新删除结点的操作
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if (head == nullptr || n == 0) return head;

ListNode *cur = head, *p = head;
for (int i = 0; p->next; i++) {
if (i >= n-1) cur = cur->next;
p = p->next;
}


// 删除cur结点的操作
if (cur->next != nullptr) { // cur不是尾结点
ListNode *delNode = cur->next;
cur->val = delNode->val;
cur->next = delNode->next;
delete(delNode);
delNode = nullptr;
} else if (cur == head) { // cur既是头结点也是尾结点
delete(cur);
cur = nullptr;
head = nullptr;
} else { // cur是尾结点
p = head;
while (p->next != cur) {
p = p->next;
}
p->next = nullptr;
delete(cur);
cur = nullptr;
}
return head;
}
};

删除链表结点的操作要记得熟练.
先讨论不是尾结点, 再讨论既是尾结点也是头结点, 最后讨论尾结点.

237. Delete Node in a Linked List - LeetCode

发表于 2018-09-03

237. Delete Node in a Linked List

Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.

Given linked list – head = [4,5,1,9], which looks like following:

4 -> 5 -> 1 -> 9

Example 1:

Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list
should become 4 -> 1 -> 9 after calling your function.

Example 2:

Input: head = [4,5,1,9], node = 1
Output: [4,5,9]
Explanation: You are given the third node with value 1, the linked list
should become 4 -> 5 -> 9 after calling your function.

Note:

  • The linked list will have at least two elements.
  • All of the nodes’ values will be unique.
  • The given node will not be the tail and it will always be a valid node of the linked list.
  • Do not return anything from your function.

Solution:

刚开始的思路是, 用被删除结点前的前一个结点prev, prev->next = node->next; 再释放node的内存。

但因为是单向链表, 只给出一个结点, 因此要删除这个结点就不能找prev结点.

将下一个结点的值赋给该结点, 该结点指向跳过下一结点, 释放下一个结点。实际上是删除了下一个结点, 但将值赋值给了当前node

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
ListNode* delNode = node->next;
node->next = delNode->next;
delete(delNode);
}
};

14. Longest Common Prefix - LeetCode

发表于 2018-09-02

14. Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings.

If there is no common prefix, return an empty string “”.

Example 1:

Input: [“flower”,”flow”,”flight”]
Output: “fl”

Example 2:

Input: [“dog”,”racecar”,”car”]
Output: “”
Explanation: There is no common prefix among the input strings.

Note:

All given inputs are in lowercase letters a-z.

Solution:

注意向量为空的情况

class Solution {
public:
string longestCommonPrefix(vector<string> &strs) {
string res = "";

for (int i = 0; strs.size() > 0; i++) {
for (int j = 0; j < strs.size(); j++) {
if ((i >= strs[j].size()) || (j > 0 && strs[j][i] != strs[j-1][i])) {
return res;
}
}
res += strs[0][i];
}
return res;
}

};

38. Count and Say - LeedCode

发表于 2018-09-02

38. Count and Say

The count-and-say sequence is the sequence of integers with the first five terms as following:

1.     1
2. 11
3. 21
4. 1211
5. 111221

1 is read off as “one 1” or 11.
11 is read off as “two 1s” or 21.
21 is read off as “one 2, then one 1” or 1211.
Given an integer n, generate the nth term of the count-and-say sequence.

Note: Each term of the sequence of integers will be represented as a string.

Example 1:

Input: 1
Output: “1”

Example 2:

Input: 4
Output: “1211”

Solution1:

用栈实现, 从低递推, 扫描一遍, 不同的数字将栈清空并加入到字符串中; 注意最后若非空栈也需要清空一次.

class Solution {
public:
string countAndSay(int n) {
if (n == 0) return "";
string ans = "1"; n--;
stack<char> stk;
while (n--) {
string temp;
int i = 0;
for (int i = 0; i < ans.length(); i++) {
if (!stk.empty() && stk.top() != ans[i]) {
temp += stk.size() + '0';
temp += stk.top();
while (!stk.empty()) stk.pop();
}
stk.push(ans[i]);
}
if (!stk.empty()) {
temp += stk.size() + '0';
temp += stk.top();
while (!stk.empty()) stk.pop();
}
ans = temp;
}
return ans;
}

};

Solution2:

在for循环中, 循环体中改变i是可行的; for语句执行的顺序是

for (进入循环之前的定义和声明等; 循环体执行条件; 循环体执行后的变量改变) {
// 循环体
}

因此, 在内部改变i, 可以使得只扫描一次.

// Time:O(n), Space:O(n)
// 指针的版本, for循环中用while跳跃
class Solution {
public:
string countAndSay(int n) {
if (n == 0) return "";
string res = "1";
while (--n) {
string cur = "";
for (int i = 0; i < res.size(); i++) {
int cnt = 1;
while ((i+1 < res.size()) && res[i] == res[i+1]) {
cnt++;
i++;
}
cur += to_string(cnt) + res[i];
}
res = cur;
}
return res;
}
};

28. Implement strStr() - LeetCode

发表于 2018-09-02

28. Implement strStr()

Implement strStr().

Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

Example 1:

Input: haystack = “hello”, needle = “ll”
Output: 2

Example 2:

Input: haystack = “aaaaa”, needle = “bba”
Output: -1

Clarification:

What should we return when needle is an empty string? This is a great question to ask during an interview.

For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C’s strstr() and Java’s indexOf()).

Solution1:

two pointers, 放在while循环中

// Time:O(n*m), Space:O(1)
class Solution {
public:
int strStr(string haystack, string needle) {
int n = haystack.length(), m = needle.length();
if (!m) return 0;

int i = 0, j = 0;
while (i < n) {
if (haystack[i] == needle[j]) {
int ok = 1, k = i;
while (k < n && j < m) {
if (haystack[k++] != needle[j++]) {
ok = 0; break;
}
}
if (ok && j == m && k <= n)
return i;
j = 0;
}
i++;
}
return -1;
}

};

Solution2:

for循环, j作为needle的下标, i作为判断的头指针, i+j是haystack的下标,

  • 1, 若两个指针指向的字符不同, 推出内层循环;
  • 2, 如果j能够在上述条件下, 到达哨兵位置, 表明完全匹配;
  • 3, 如果i+j到了haystack的哨兵位置, 扫描结束, 未找到;
// Time:O(n*m), Space:O(1)
class Solution {
public:
int strStr(string haystack, string needle) {
for (int i = 0; ; i++) {
for (int j = 0; ; j++) {
if (j == needle.length()) return i;
if (i+j == haystack.length()) return -1;
if (haystack[i+j] != needle[j]) break;
}
}
}
};

根据这个思路, 对Solution1进行简化,

  • 用达到哨兵位置取代对ok变量的操作;
  • 用i+j取代新增的k变量;
  • i的范围在n-m之内.
// 第一个版本的简化版本
// Time:O(n*m), Space:O(1)
class Solution {
public:
int strStr(string haystack, string needle) {
int n = haystack.length(), m = needle.length();
if (!m) return 0;

int i = 0, j = 0;
while (i <= n-m) {
if (haystack[i] == needle[j]) {
while (j < m && haystack[i+j] == needle[j]) j++;
if (j == m) return i;
j = 0;
}
i++;
}
return -1;
}
};
1…345…18

mituh

179 日志
99 标签
© 2018 mituh
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4