使用的存储空间尽量小。
#include <iostream> #include <algorithm> using namespace std; class data { public: unsigned int first; unsigned int second; friend bool operator<( const data & d1, const data& d2); }; inline bool operator<( const data & d1, const data& d2) { return d1.first < d2.first; } int foo(unsigned int *a1, int al1, unsigned int* a2, int al2) { data * d1 = (data*) a1; data * d2 = (data*) a2; sort(d1, d1+al1/2, less<data>()); sort(d2, d2+al2/2, less<data>()); int len = 0; for( int i =0, j = 0; (i < al1/2 && j < al2/2);) { if(d1[i].second <= d2[j].first) { i++; } else if(d1[i].first >= d2[j].second) { j++; } else { if(d1[i].first <= d2[j].first && d2[j].second <= d1[i].second) { len += d2[j].second - d2[j].first; j++; } else if(d2[j].first <= d1[i].first && d2[j].second >= d1[i].second) { len += d1[i].second - d1[i].first; i++; } else if( d1[i].first >= d2[j].first && d1[i].first < d2[j].second && d1[i].second >= d2[j].second) { len += d2[j].second - d1[i].first; j++; } else if( d2[j].first >= d1[i].first && d2[j].first < d1[i].second && d2[j].second >= d1[i].second) { len += d1[i].second - d2[j].first; i++; } } } return len; } int main() { unsigned int a1[] = { 0, 1, 3, 6, 10, 20}; unsigned int a2[] = { 0, 1, 20,50, 4, 5}; int len = foo( a1, 6, a2, 6); cout << "len: " << len << endl; return 0; }
2. 多人排成一个队列,我们认为从低到高是正确的序列,但是总有部分人不遵守秩序。如果说,前面的人比后面的人高(两人身高一样认为是合适的)
那么我们就认为这两个人是一对“捣乱分子”,
比如说,现在存在一个序列:
176, 178, 180, 170, 171
这些捣乱分子对为 <176, 170>,<176, 171>,<178, 170>,<178, 171>,<180, 170>,<180, 171>
那么,现在给出一个整型序列,请找出这些捣乱分子对的个数(仅给出捣乱分子对的数目即可,不用具体的对)
要求:
输入:
为一个文件(in),文件的每一行为一个序列。序列全为数字,数字间用”,”分隔。
输出:
为一个文件(out),每行为一个数字,表示捣乱分子的对数。
详细说明自己的解题思路,说明自己实现的一些关键点。并给出实现的代码 ,并分析时间复杂度。
限制:
输入每行的最大数字个数为100000个,数字最长为6位。程序无内存使用限制。
归并的方法求数组的逆序数。
#include <iostream> using namespace std ; void merge(int * a, int *p, int start, int mid, int end, int & count) { int i = 0, j = 0; for(i = start; i <= mid; i++) // 将数据复制到辅助空间 p[i] = a[i] ; for(j = mid + 1; j <= end; j++) p[j] = a[j]; i = start; j = mid + 1; int w = start; while( i <= mid && j <= end) { if(p[i] <= p[j]) { a[w++] = p[i++]; } else { count += mid - i + 1; //注意此处的处理 a[w++] = p[j++]; } } while(i <= mid) { a[w++] = p[i++]; } while(j <= end) { a[w++] = p[j++]; } } void mergeSort(int *a, int *p, int start, int end, int &count) { if(start < end) { int mid = ( start + end) / 2; mergeSort( a, p, start, mid, count); mergeSort( a, p, mid + 1, end, count); merge( a, p, start, mid, end, count); } } int main() { int a[5]; int n = 5; int * p = new int[5]; if(n > 0) { int count = 0; for(int i = 0; i < n; i++) { a[i] = rand(); cout << a[i] << " "; } cout << endl; mergeSort( a, p, 0, n - 1, count); cout << count << endl; } delete [] p; return 0; }
思路:就是将前半段比后半段大的元素,在后半段进行插入排序(从前向后插入,而不是从后往前),此处注意一个问题,在拿前面元素向后半段插入时,后半段肯定有空间可用,因为已经将它的一个元素放入了前半段有序数组中。
#include <iostream> using namespace std ; void merge(int a[], int len) { int mid = len / 2; for( int i = 0, j = mid; i < mid; ) { if( a[i] <= a[j]) // 前半部分的大 { i++; } else { int tmp = a[i]; a[i] = a[j]; i++; int index = j + 1; if( tmp <= a[index]) { a[j] = tmp; } else { while(tmp > a[index] && index < len) { a[index - 1] = a[index]; index ++; } a[index-1] = tmp; } }// end of else }// end of for } int main() { int a[10] = {1, 3, 5, 9, 13, 4, 7, 11, 12, 19}; for( int i = 0; i < 10; i++) { cout << a[i] << " "; } cout << endl; merge(a, 10); for( int i = 0; i < 10; i++) { cout << a[i] << " "; } cout << endl; return 0; }
4. 随机输入一个数,判断它是不是对称数(回文数)(如3,121,12321,45254)。不能用字符串库函数
思路: 首先将数字转化为字符串(由于只是判断是否是回文数,因此转化为字符串之后的正序逆序并不重要),然后判断字符串是否是对称的。
#include <iostream> using namespace std ; bool IsSymmetry(char * str) { int len = strlen(str); char * p = str, *q = str+len-1; while(p < q) { if( *p == *q) { p++; q--; } else { return false; } } return true; } void int2str(int n, char * str) { if(n <= 0 || str == NULL) { return ; } int index = 0; while(n > 0) { str[index++] = '0' + n % 10; n /= 10; } return ; } int main() { int input; cout << "Input a number:"; cin >> input; cout << endl; char str[256]; memset(str, 0, sizeof(str)); int2str(input, str); if(IsSymmetry(str)) { cout << "回文数" << endl; } else { cout << "非回文数" << endl; } return 0; }
解答:
一个生产者,三个消费者,公用 1 个缓冲区
在这个问题中,不仅生产者与消费者之间要同步,同时每生产一个产品,三个消费者必须并且只能消费一次。
定义四个信号量:
mutexB—— 消费者 B 和生产者之间的互斥信号量,初值为 1 。
mutexC—— 消费者 C 和生产者之间的互斥信号量,初值为 1 。
mutexD—— 消费者 D 和生产者之间的互斥信号量,初值为 1 。
// 生产者进程 while(TRUE) { 生产一个产品 ;// 因为这里需要确认三个消费者都已经消费了
P(mutexB);
P(mutexC);
P(mutexD);
产品送往 buffer();
// 三个消费者可以消费了
V(mutexB);
V(mutexC);
V(mutexD);
}// 消费者进程 B ,每个产品,该消费者只能消费一次while(TRUE){ P(mutexB); 从 buffer() 中取出产品 ; V(mutexB); 消费该产品 ;}// 消费者进程 C ,每个产品,该消费者只能消费一次while(TRUE){ P(mutexC); 从 buffer() 中取出产品 ; V(mutexC); 消费该产品 ;}// 消费者进程 D, 每个产品,该消费者只能消费一次while(TRUE){ P(mutexD); 从 buffer() 中取出产品 ; V(mutexD); 消费该产品 ;}
By Andy @ 2013-9-28