出题:给定链表的头指针和一个节点指针,要求在O(1)的时间复杂度下删除该节点
分析:
- 如果需要删除的节点为A,其前序节点为A-,其后续节点为A+,所以删除A之后,需要使得A-的下一个节点就是A+,常规做法是设法得到A-的索引,需要 从链表头开始遍历所以时间复杂度为O(N),但实际情况是只要保证A-的下一个节点是A+就行;
- 所以可将A+节点的内容直接复制到A节点,这时时间复杂度 为O(1),对于最后一个节点而言需要使用O(N)的时间复杂度,所以平均复杂度为(O(1)*(n-1) + O(n))/n,所以平均复杂度为O(1);
解题:
1 struct Node { 2 int v; 3 Node *next; 4 }; 5 6 void deleteNode(Node *head, Node *target) { 7 if(target == NULL) return; 8 if(target->next != NULL) { 9 Node *temp=target->next; 10 target->v=temp->v; 11 target->next=temp->next; 12 delete temp; 13 } else { 14 Node *temp=head; 15 while(temp!=NULL) { 16 if(temp->next != target) 17 temp=temp->next; 18 else { 19 temp->next=temp->next->next; 20 delete target; 21 break; 22 } 23 } 24 } 25 }
出题:给定一个整型数组,除了两个数字只出现一次外其他数字都出现了两次,要求确定这个两个只出现一次的数字,时间复杂度为O(N),空间复杂度为O(1);
分析:
- 由于任何一个数字异或它本身的结果都为0,所以从左到右依次异或整型数组,数组中出现两次的数字的异或结果为0,则最终的结果就是出现一次的两个数字的异 或结果;由于这两个数字肯定不同,所以结果肯定非0,为了将这两个数字分别放到一个子数组中,选取结果中第一个出现的1(第k位),这样根据第k位是否为 1将数组元素分成两个子数组,他们分别包含了一个只出现一次的数字,然后针对每一个子数组重新进行异或运算,最终就可分别得到这两个仅出现一次的数字;
- 本题参考何海涛老师的解法,海涛老师威武!!非常感谢何海涛老师的无私奉献,其博客地址为:
http://zhedahht.blog.163.com/
解题:
1 void findInteger(int *array, int length) { 2 /** 3 * 获取整个数组的异或结果 4 * sum1为两个目标数字的异或结果 5 * */ 6 int sum1=array[0]; 7 for(int i=1;i<length;i++) 8 sum1^=array[i]; 9 /** 10 * 找到sum1中最低位出现的1 11 * k表示目标位上出现的1 12 * */ 13 int k=1,i; 14 for(i=0;i<sizeof(int)*8;i++) { 15 if(sum1 & k<<i) break; 16 } 17 k<<=i; 18 /** 19 * 使用k区分不同的子数组 20 * 分别对子数组使用异或 21 * */ 22 int int1=1, int2=1; 23 for(int i=0;i<length;i++) { 24 if(array[i]&k) 25 int1^=array[i]; 26 else 27 int2^=array[i]; 28 } 29 int1^=1;int2^=1; 30 printf(" the first integer: %d",int1); 31 printf(" the second integer: %d",int2); 32 } 33 34 int main() { 35 int array[]={11,22,11,22,23,-9,-9,15}; 36 findInteger(array,8); 37 return 0; 38 }