笔试算法题(18):常数时间删除节点 & 找到仅出现一次的两个数字

出题:给定链表的头指针和一个节点指针,要求在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("\nthe first integer: %d",int1);
31         printf("\nthe 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 }

 

posted @ 2014-05-21 09:27  Leo C.  阅读(163)  评论(0编辑  收藏  举报