zoukankan      html  css  js  c++  java
  • 笔试算法题(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("
    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 }
  • 相关阅读:
    求所有科目都大于80分的学生姓名
    sql server如何设置密码过期时间呢?
    sql server官网使用查找技术文档(msdn、联机丛书)
    【版本特性】sql server2014版本特性
    SQLSERVER文件组误脱机后如何联机
    sql server2014中的内存优化表/内存表(续写)
    JNI日志调试LOG和中文乱码
    JNI常见错误整理
    什么是“软解码”,什么又是“硬解码”呢?
    创建eclipse针对NDK的联合编译环境。
  • 原文地址:https://www.cnblogs.com/leo-chen-2014/p/3740580.html
Copyright © 2011-2022 走看看