前段时间参加了牛客网的答题活动,共两套试题,每套题目3个算法题,我只做了每套题的前两道。最近想查看之前做的题目的答案,却发现非常不方便,特此将我做过的4道题目记录一下,算法的思路就不再解释了。
题目一 奇数位上都是奇数或者偶数位上都是偶数
给定一个长度不小于2的数组arr。 写一个函数调整arr,使arr中要么所有的偶数位上都是偶数,要么所有的奇数位上都是奇数上。 要求:如果数组长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1),下标0,2,4,6…算作偶数位,下标1,3,5,7…算作奇数位,例如[1,2,3,4]调整为[2,1,4,3]即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution {public : void oddInOddEvenInEven (vector<int >& arr, int len) { int odd = 1 ; int even = 0 ; while (odd < len && even < len) { if (arr[odd] % 2 == 0 ) { while (arr[even] % 2 == 0 ) { even += 2 ; } if (even < len) { int tmp = arr[even]; arr[even] = arr[odd]; arr[odd] = tmp; } else { break ; } } else { odd += 2 ; } } } };
题目二 求正数数组的最小不可组成和
给定一个全是正数的数组arr,定义一下arr的最小不可组成和的概念: 1,arr的所有非空子集中,把每个子集内的所有元素加起来会出现很多的值,其中最小的记为min,最大的记为max; 2,在区间[min,max]上,如果有一些正数不可以被arr某一个子集相加得到,那么这些正数中最小的那个,就是arr的最小不可组成和; 3,在区间[min,max]上,如果所有的数都可以被arr的某一个子集相加得到,那么max+1是arr的最小不可组成和; 举例: arr = {3,2,5} arr的min为2,max为10,在区间[2,10]上,4是不能被任何一个子集相加得到的值中最小的,所以4是arr的最小不可组成和; arr = {3,2,4} arr的min为2,max为9,在区间[2,9]上,8是不能被任何一个子集相加得到的值中最小的,所以8是arr的最小不可组成和; arr = {3,1,2} arr的min为1,max为6,在区间[2,6]上,任何数都可以被某一个子集相加得到,所以7是arr的最小不可组成和; 请写函数返回arr的最小不可组成和。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution {public : int getFirstUnFormedNum (vector<int >& arr, int len) { set<int > res; for (int i=0 ; i<len; i++) { set<int > tmp = res; for (set<int >::iterator iter = res.begin (); iter != res.end (); iter++) { tmp.insert (*iter + arr[i]); } res = tmp; res.insert (arr[i]); } set<int >::iterator iter = res.begin (); int before = *iter; iter++; for (; iter != res.end (); iter++) { if (*iter - before > 1 ) { return before + 1 ; } before = *iter; } return before + 1 ; } };
题目三 最大的LeftMax与rightMax之差绝对值
给定一个长度为N的整型数组arr,可以划分成左右两个部分: 左部分arr[0..K],右部分arr[K+1..arr.length-1],K可以取值的范围是[0,arr.length-2] 求这么多划分方案中,左部分中的最大值减去右部分最大值的绝对值,最大是多少? 例如: [2,7,3,1,1] 当左部分为[2,7],右部分为[3,1,1]时,左部分中的最大值减去右部分最大值的绝对值为4; 当左部分为[2,7,3],右部分为[1,1]时,左部分中的最大值减去右部分最大值的绝对值为6; 最后返回的结果为6。 注意:如果数组的长度为N,请尽量做到时间复杂度O(N),额外空间复杂度O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution {public : int getMaxABSLeftAndRight (vector<int > vec, int len) { if (len == 0 ) { return 0 ; } int max = vec[0 ]; for (int i=1 ; i<(int )vec.size (); i++) { if (vec[i] > max) { max = vec[i]; } } if (vec[0 ] < vec[len - 1 ]) { return max - vec[0 ]; } return max - vec[len - 1 ]; } };
题目四 按照左右半区的方式重新组合单链表
给定一个单链表的头部节点head,链表长度为N。 如果N为偶数,那么前N/2个节点算作左半区,后N/2个节点算作右半区; 如果N为奇数,那么前N/2个节点算作左半区,后N/2+1个节点算作右半区; 左半区从左到右依次记为L1->L2->…,右半区从左到右依次记为R1->R2->…。请将单链表调整成L1->R1->L2->R2->…的样子。 例如: 1->2->3->4 调整后:1->3->2->4 1->2->3->4->5 调整后:1->3->2->4->5 要求:如果链表长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution {public : void relocateList (struct ListNode* head) { if (head == NULL || head->next == NULL ) { return ; } ListNode *right_head = head; ListNode *node = head; while (node != NULL ) { if (node->next == NULL ) { break ; } if (node->next->next == NULL ) { right_head = right_head->next; break ; } right_head = right_head->next; node = node->next->next; } ListNode *left_node = head; ListNode *right_node = right_head; while (left_node->next != right_head) { ListNode *tmp = left_node->next; left_node->next = right_node; right_node = right_node->next; left_node->next->next = tmp; left_node = left_node->next->next; } left_node->next = right_node; } };