(转)经典面试题

UCOSii(五)——内存管理 一、前言在嵌入式系统中,时常会面临Ram受限的情况。所以用C lib里的,malloc()和 free()来申请和释放内存时,频繁的内存请求造成的内存碎片会对系统性能造成负面影响。Ucos的解决办法是为内存划分不同大小的内存区域,每个区域内有一定数量、相同大小的内存块。每次申请内存都必须要以一个内存块为单位,释放内存块时,该内存块会回到相应的内存分区。这样,确实,内存的碎片的问题得到了一定程度的解决 阅读详情

1.        有一个整数数组,请求出两两之差绝对值最小的值。记住,只要得出最小值即可,不需要求出是哪两个数。(Microsoft) 

方法1:两两作差求绝对值,并取最小,O( n2 )。

方法2:排序,相邻两点作差求绝对值,并取最小,O( nlgn ).

方法3:有没有O( n )的解法?网上有如下解法:

设数组A = { a1, a2, … , an }, 求 s = min( |ai - aj| ), 其中1<= i, j <=n.

设B = { b1, b2, … , bn-1 }, 且 bi = ai – ai+1

即:b1 = a1 – a2, b2 = a2 – a3, b3 = a3 – a4, …

 

于是有如下规律:

例如:a3 – a5 = ( a3 – a4 ) + ( a4 – a5 ) =b3 + b4

a1 – a6 = b1 + b2 + … + b5

即:ai – aj = bi + … + bj-1

则数组A中任意两个数的差,都可以用数组B中一个字段的和表示。

则原问题可以转换为:

在数组B中,求连续的某一段,使其和的绝对值最小。(只求最小值,不需要知道具体是哪些数)

例如 B = { 1, -2, 3, -1, -9, 7, -5, 6 };

则绝对值最小值为0,具体是{ -2, 3, -1 } 或 {3, -1, -9, 7}

 

网上的解法,一般到这里就没下文了。只是简单的提了一下,类似于最大子序列的和。具体怎么做,还要自己想想。

最大子序列和利用DP,可O( n )求解。这题咋做?纠结。

 

2.        写一个函数,检查字符是否是整数,如果是,返回其整数值。(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?) 

据说此题是,Microsoft的大牛只有了4行代码就给出了答案。

可惜,不知道是怎么写的。自己试着写写,当然可能会不至4行。单纯追求行数,也没什么意义,如果你愿意可以把所有的程序都写成一行。

注意:

1. 处理前导空格

2. 处理正负号

3. 处理进制(16进制、8进制、10进制)

4. 非法字符( 0---9, a---f, A---F)

5. 注意整数的范围,不能溢出 

[cpp]  view plain copy
  1. bool StrToInt( char *pc, long &value )  
  2. {  
  3.     //去掉前导空格  
  4.     while( ( *pc==' ' || *pc=='\t' ) && *pc != '\0' ) pc++;  
  5.     if( *pc == '\0' )   return false;  
  6.   
  7.     //处理正负号  
  8.     int sign = 1;  
  9.     if( *pc == '+' || *pc == '-' )  
  10.     {  
  11.         if( *(pc+1) =='\0' ) return false;  
  12.         if( *pc == '-' ) sign = -1;   
  13.         pc++;  
  14.     }  
  15.   
  16.     //处理数值  
  17.     long tmp = 0;  
  18.     while( *pc != '\0' )  
  19.     {  
  20.         tmp *= 10;  
  21.         //++优先级比*高  
  22.         if( *pc < '0' && *pc > '9' ) return false;          
  23.         tmp += ( *pc++ - '0' );  
  24.     }  
  25.     value = tmp * sign;  
  26.     return true;  
  27. }  

3.        给出一个函数来输出一个字符串的所有排列 

方法1:

一个简单的DFS。从后往前不断交互。N个字母求全排列,O( n! )。具体实现,看代码吧。

方法2:

如果不会写递归,也可以利用STL。STL里有一个next_permutation函数。利用这个函数可以返回大于原字符串的下一个字典序列。当字符串为最大字典序列时,函数返回false。这样只要先对原字符串排序,然后不断调用next_permuation即可。

[cpp]  view plain copy
  1. inline void Exchange( char *px, char *py )  
  2. {  
  3.     char tmp = *px;  
  4.     *px = *py;  
  5.     *py = tmp;  
  6. }  
  7.   
  8. void PrintStrPermut( char *pstr, char *pbegin )  
  9. {  
  10.     //处理空字符串  
  11.     if( pstr == NULL || pbegin == NULL ) return;  
  12.   
  13.     //递归终止条件  
  14.     if( *pbegin == '\0' )  
  15.         cout << pstr << endl;  
  16.     else  
  17.     {  
  18.         for( char *p=pbegin; *p!='\0'; p++ )  
  19.         {  
  20.             Exchange( p, pbegin );  
  21.             PrintStrPermut( pstr, pbegin+1 );  
  22.             Exchange( p, pbegin );  
  23.         }  
  24.     }  
  25. }  
  26.   
  27. void PrintStrPermut2( char *pstr )  
  28. {  
  29.     char *p = pstr;  
  30.     while( *p != '\0' ) p++;  
  31.   
  32.     sort( pstr, p );  
  33.     cout << pstr << endl;  
  34.     while( next_permutation( pstr, p ) )  
  35.     {  
  36.         cout << pstr << endl;  
  37.     }  
  38. }  

4.请编写实现malloc()内存分配函数功能一样的代码  

这题比较难,要是不懂点OS的内存管理,根本就无从下手。

我们知道调用malloc()后,OS就要想方设法为我们返回一块空闲空间。这就涉及到OS的内存管理。OS的内存管理可以这样考虑:

假设整块内存有128K

初始状态,128K都是空闲

第一次请求,申请了16k,空闲112K

第二次请求,申请了32K,空闲80K

第三次请求,申请了8K,空闲72K

第二次请求申请的32K被释放,空闲108K

第四次请求,申请了24K,空闲84K

…

从上面的例子可以看出,一整块连续的空闲内存块,经过一段时间的使用,会被无情的划分为许多小块。这些小块大小不等,并且有的空闲、有的被占用。

当调用malloc时,OS就沿内存扫描,找到一块够大的空闲块,从中划分出要使用的部分,将这部分标记为己分配,并返回这部分的首地址。如果,空闲的块都是些小的碎片,那就悲具了(当然,OS可以把将相邻的空闲块合并,再尝试)。

 

现在,模拟一下malloc的过程:

为了便于管理,首先定义内存控制块mcb。这个mcb记录两个信息:块是否空闲、块的大小。即,每个分配出去的块,其实都带有一个mcb,只不过这个mcb位于块的最前端,返回该用户的指针刚好指向mcb之后,所以对用户是不可见的。

现在,就可以处理free了。Free只要把已分配的内存块重新标记为空闲即可,这里当然要用到该快的mcb了。

Malloc简单来说,就是维护几个指针,根据分配请求修改指针位置。对于要分配的块,将标记置位己分配,并返回这部分的首地址。

参考http://lklkdawei.blog.163.com/blog/static/32574109200881445518891/,这里讲的很清楚,还附有代码,我就不狗尾续貂了。

5. 字符串A的后几个字节和字符串B的前几个字节重叠。 

这题似乎没什么玄机,就是个简单的字符串处理。使用strlen和memcpy可以完成,见代码。 

[cpp]  view plain copy
  1. bool StrOverlap( char *strA, char *strB, int cnt, char *strC )  
  2. {  
  3.      int sizeA = (int)strlen( strA );  
  4.      int sizeB = (int)strlen( strB );  
  5.   
  6.      if( cnt > sizeA || cnt > sizeB ) return false;  
  7.   
  8.      memcpy( strC, strA, sizeA-cnt );  
  9.      memcpy( strC+sizeA-cnt, strB+cnt, sizeB-cnt );  
  10.   
  11.      //注意添加结束标记  
  12.      strC[sizeA+sizeB-2*cnt] = '\0';  
  13.      return true;  
  14. }  


6. 怎样编写一个程序,把一个有序整数数组放到二叉树中? 

由数组建立排序二叉树。因为数组已排序,所以可以进行类似排序二叉树上的查找。感觉有点类似先序遍历,每次先处理根节点,然后分别是左子树、右子树。具体做法是:

1.整个数组对应一个二叉树,则中间元素对应二叉树的根节点

2.中间元素左边的部分对应左子树、右边的部分对应右子树

3.对左右两部分再继续递归调用。 

[cpp]  view plain copy
  1. struct BiTreeNode   
  2. {  
  3.     int data;  
  4.     BiTreeNode* leftChild;  
  5.     BiTreeNode* rightChild;  
  6.   
  7.     //构造函数,初始化成员变量  
  8.     BiTreeNode(): data(0), leftChild(0), rightChild(0){};  
  9. };  
  10.   
  11. void ArrayToTree( int *pi, int left, int right, BiTreeNode *&root )  
  12. {  
  13.     if( left <= right )  
  14.     {  
  15.         int mid = ( left + right ) / 2;  
  16.         root = new BiTreeNode;  
  17.         root->data = pi[mid];  
  18.   
  19.         ArrayToTree( pi, left, mid-1, root->leftChild );  
  20.         ArrayToTree( pi, mid+1, right, root->rightChild );  
  21.     }     
  22. }  


7. 怎样从顶部开始逐层打印二叉树结点数据?请编程。 

用队列容易实现。网上有人说有非队列的实现,不过还是用指针把每一层的点都连了起来,然后逐层打印。这种方法和用队列把每层的节点存起来大同小异。
[cpp]  view plain copy
  1. void PrintTreeByLevel( BiTreeNode *&root )  
  2. {  
  3.     if( root != NULL )  
  4.     {  
  5.         queue<BiTreeNode> que;  
  6.         que.push( *root );  
  7.   
  8.         while( !que.empty() )  
  9.         {  
  10.             BiTreeNode curNode = que.front();  
  11.             que.pop();  
  12.             cout << curNode.data << " ";  
  13.               
  14.             if( curNode.leftChild != NULL ) que.push( *curNode.leftChild );  
  15.             if( curNode.rightChild != NULL ) que.push( *curNode.rightChild );  
  16.         }  
  17.     }     
  18. }  

8.怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)? 

这题主要看有没有额外存储空间的限制。

如果没有,可以重新生成一个链表,该链表是原链表的反序。具体做的时候,每次只需把新节点插入的头结点的前面即可。此时,空间复杂度O(n).

如果有存储空间的限制,要求为O(1),即只能用常数个辅助变量。这时可以用三个指针来实现。首先,需要一个指针cur,指向要反向的节点。因为链表反序,指针要指向前一个,而单链表无法直接得到前一个,所以需要一个指针pre。然后,当指针cur反向后,就无法指向下一个,所以需要一个指针next,用于保存cur的下一个。这样只要遍历整个链表,不断使指针cur所指节点反向即可。 

[cpp]  view plain copy
  1. struct ListNode  
  2. {  
  3.     int data;  
  4.     ListNode *next;  
  5.   
  6.     ListNode(): data(0), next(0) {};  
  7. };  
  8.   
  9. //假设没有哨兵元素  
  10. ListNode* ReverseList( ListNode *head )  
  11. {  
  12.     //空链表   
  13.     if( head == NULL ) return NULL;  
  14.   
  15.     //只有一个元素的链表  
  16.     if( head->next == NULL ) return head;  
  17.   
  18.     //至少有两个元素  
  19.     ListNode *pre, *cur, *next;  
  20.     pre = head;  
  21.     cur = pre->next;   
  22.     next = NULL;  
  23.   
  24.     while( cur != NULL )  
  25.     {  
  26.         //保存下一个节点的指针  
  27.         next = cur->next;  
  28.   
  29.         cur->next = pre;  
  30.         pre = cur;  
  31.         cur = next;  
  32.     }     
  33.     head->next = NULL;  
  34.     head = pre;  
  35.     return head;  
  36. }  

 

9.请编写能直接实现int atoi(const char * pstr)函数功能的代码。 

需要注意的问题:

1.前导白空

2.正负号

3.不同进制

4.非法字符

5.Int范围 

[cpp]  view plain copy
  1. int MyAtoi(const char * pstr)  
  2. {  
  3.     //去除前导空格  
  4.     while( *pstr == ' ' || *pstr == '\t' ) pstr++;  
  5.   
  6.     //判断正负号  
  7.     int sign = 1;  
  8.     if( *pstr == '+' || *pstr == '-' )  
  9.     {  
  10.         if( *pstr == '-' ) sign = -1;  
  11.         pstr++;  
  12.     }  
  13.   
  14.     //判断进制  
  15.     int base = 10;  
  16.     if( *pstr == '0' )  
  17.     {  
  18.         pstr++;  
  19.   
  20.         //以0开头的为八进制  
  21.         base = 8;  
  22.         //以0x开头的为16进制  
  23.         if( *pstr == 'X' || *pstr == 'x' )  
  24.         {  
  25.             base = 16;  
  26.             pstr++;  
  27.         }  
  28.     }  
  29.   
  30.     //处理数值部分,注意非法字符  
  31.     long value = 0;  
  32.     while( *pstr != '\0' )  
  33.     {  
  34.         if( base == 10 && ( *pstr < '0' || *pstr > '9' ) ||  
  35.             base == 8 && ( *pstr < '0' || *pstr > '7' ) ||  
  36.             base == 16 && !( ( *pstr >= '0' && *pstr <= '9' ) ||   
  37.                              ( *pstr >= 'A' && *pstr <= 'F' ) ||    
  38.                              ( *pstr >= 'a' && *pstr <= 'f' ) )  
  39.            )   
  40.            return 0;          
  41.   
  42.          value *= base;  
  43.   
  44.          if( base == 16 )  
  45.          {  
  46.              if( *pstr >= '0' && *pstr <= '9' ) value += ( *pstr - '0' );  
  47.              if( *pstr >= 'a' && *pstr <= 'f' ) value += ( *pstr - 'a' ) + 10;  
  48.              if( *pstr >= 'A' && *pstr <= 'F' ) value += ( *pstr - 'A' ) + 10;  
  49.          }  
  50.          else  
  51.          {  
  52.              value += *pstr - '0';  
  53.          }  
  54.          pstr++;  
  55.     }  
  56.          //判断是否溢出  
  57.     if( value > INT_MAX || value < INT_MIN ) return 0;  
  58.       
  59.     return value * sign;  
  60. }  

 

10.编程实现两个正整数的除法,当然不能用除法操作符。

// return x/y.

int div(const int x, const int y)

{

  ....

}

 

a/b=x, 即求a里面有多少个b.

方法一:枚举,b*1,b*2,b*3,…,直到b*x == a 或 b*x < a && b*(x+1) > a,复杂度O( a/b)这样

方法二:

除了x = 1+…+1(x个1相加),x还可以用2的幂的和表示(如4 = 2^2, 7 = 2^2+2+1 )。不用逐一枚举,类似折半查找。不断划分区间,用区间比较。

不断尝试b*(1<<0),b*(1<<1),b*(1<<2),…,

直到b*(1<<m) < a && b*(1<<m+1) > a,

则从a - b*(1<<m),然后再重新开始。 

[cpp]  view plain copy
  1. int Div( const int x, const int y )  
  2. {  
  3.     if( x < y ) return 0;  
  4.   
  5.     int tmp = x;  
  6.     int ans = 0;      
  7.   
  8.     while( tmp >= y )  
  9.     {  
  10.         int cnt = 1;  
  11.         while( ( y * cnt ) <= tmp )  cnt <<= 1;  
  12.           
  13.         cnt >>= 1;  
  14.         ans += cnt;  
  15.         tmp -= y * cnt;  
  16.     }  
  17.     return ans;  
  18. }  

 

11.在排序数组中,找出给定数字的出现次数。比如[1, 2, 2, 2, 3] 中的出现次数是次。 

方法一:直接遍历,首先找到这个数,然后逐一计数,O(n)可完成。

方法二:二分查找,首先找到这个数的第一个,记录其位置。再二分查找,找到这个数的最后一个,记录其位置。最后下边相减,O(lgn)可完成。虽然两次都是二分查找,但还是略微有点区别。

LowerSearch把相等的情况划归到左半部分,所以计算mid时要向下取整。

UpperSearch把相等的情况划归到右半部分,所以计算mid时要向上取整。 

[cpp]  view plain copy
  1. //target出现的第一个位置  
  2. int LowerSearch( int *pi, int left, int right, int target )  
  3. {     
  4.     while( left < right )  
  5.     {  
  6.         //mid向下取整  
  7.         int mid = ( left + right ) / 2;  
  8.   
  9.         if( target <= pi[mid] )  
  10.         {  
  11.             right = mid;  
  12.         }  
  13.         else  
  14.         {  
  15.             left = mid + 1;  
  16.         }  
  17.     }  
  18.     return left;  
  19. }  
  20. //target出现的第最后一个位置  
  21. int UpperSearch( int *pi, int left, int right, int target )  
  22. {  
  23.     while( left < right )  
  24.     {  
  25.         //这里mid向上取整  
  26.         int mid = ( left + right + 1 ) / 2;  
  27.   
  28.         if( target >= pi[mid] )  
  29.         {  
  30.             left = mid;  
  31.         }  
  32.         else  
  33.         {  
  34.             right = mid - 1;  
  35.         }         
  36.     }  
  37.     return left;  
  38. }  
  39.   
  40. int GetCount( int *pi, int left, int right, int target )  
  41. {  
  42.     int first = LowerSearch( pi, left, right, target );  
  43.     int second = UpperSearch( pi, left, right, target );  
  44.   
  45.     return second-first+1;  
  46. }  

12.平面上N个点,每两个点都确定一条直线,求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。 

按照一般的方法,逐个求斜率比较,O(n^2)可完成。有没有更快的方法?有。

对所有的点按x坐标排序,然后只比较相邻两点的斜率即可。复杂度O( nlgn )。当然,只要有了算法,编程实现很容易,关键是为什么?

我不会严格的证明,只能朴素的理解一下。

设有三个点A、B、C

如果A、B、C在一条直线上,则斜率相等

如果A、B、C不在一条直线上,则构成三角形ABC。不妨设Xa < Xb < Xc

即按照x坐标排序后,A、B相邻,B、C相邻。也就是说,三角形中AC为最长边。如图,显然Kab和Kbc中至少有个大于Kac.

 

13.一个整数数列,元素取值可能是~65535中的任意一个数,相同数值不会重复出现。是例外,可以反复出现。

请设计一个算法,当你从该数列中随意选取个数值,判断这个数值是否连续相邻。

注意:

- 5个数值允许是乱序的。比如:8 7 5 0 6

- 0可以通配任意数值。比如:7 5 0 6 中的可以通配成或者

- 0可以多次出现。

- 复杂度如果是O(n2)则不得分。

 

首先对这5个数进行排序。

如果5个数中没有0,那么用最大值 – 最小值。如果差值= 4,则连续。否则,不连续。

如果5个数中有0,则0必然排在最前面。依旧最大值 – 最小值。当差值取1,说明只有2个非0数,必然连续,则其余的数都可用0补齐。那么在连续的情况下差值最大取多少?最大值为4。这时必然有一个数不连续,但是可以用0补.

综上:

1.      先排序

2.      用非零最大值 - 非零最小值,如果差值<=4,则连续。否则,不连续。

3.      处理没有非零最大值或非零最小值的情况。

A.      全为零,必连续  B. 只用一个非0值,也连续 

14.设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分。 

       经典的LCA问题,有非常成熟的解法,用tarjan算法或转换为RMQ问题。Tarjan自己没写过。这里是RMQ的解法。对于RMQ也有多种解法,比如线段树、ST等。这里讨论一下ST算法。

RMQ问题:RMQ( A, i, j )表示在数组A中求A[i]…A[j]之间最小值的下标。 

 

        首先,把LCA转换为RMQ问题。

        对二叉树进行DFS,记录每个节点被访问的顺序。因为有回溯,除了根节点,每个节点都被访问2次。设二叉树有n个节点,则DFS完成后回记录2n-1个节点,然后由这些节点构成数组path,该数字记录了DFS遍历节点的顺序。

       在进行DFS时,同时记录各节点的层数,组成数组level。

       对二叉树上的任意两点x和y, 找到x 、y在数组path中第一次出现的位置,记为pos(x), pos(y)。则path[ pos(x) ]…path[ pos(y) ]代表在二叉树上从x遍历到y的一条路径,那么该路径上level最小的点就是x 、y的LCA。

即LCA( A, i, j ) = RMQ( level, pos(x), pos(y) )

 

       RMQ问题的ST求解。ST,实质上属于DP。

定义:dp[i][j]表示数字A中,A[i]…A[i+2^j-1]中(即由A[i]开始的连续2^j个元素)最小值的下标

状态转换方程:dp[i][j] = Min( dp[i][j-1], dp[i+2^(j-1)][j-1] );

大概解释一下:状态方程把A[i]…A[i+2^j-1]共2^j个元素,分成两部分A[i]…A[i+2^(j-1)-1]和A[[i+2^(j-1)]…A[j],每部分2^( j-1 )个元素,然后取两部分的最小值即可。

       上述部分,其实就是个DP的预处理过程。完成了预处理,最后就是RMQ问题的求解, RMQ( A, i, j ) = ?

       有了上述的dp[][],只要想办法把A[i]…A[j]分成两部分,使每部分的长度为2^k。这样就可以查dp[][]数组了。对于这两部分有什么要求吗?两部分合起来刚好覆盖整个[ i, j ]区间,这当然是最好的了。但是,有时很难取到整数,所以连部分通常是交叉的,甚至每一部分几乎覆盖了整个区间。

即,2^k = j - i + 1,则可求 k=lg( j-i+1 )。k是下取整。

最终:RMQ( A, i, j ) = Min( dp[i][k], dp[j-2^k+1][j] )

RMQ的ST求解见代码

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. const int MAX = 100;  
  5.   
  6. //dp[i][j] 表示从i开始到为i+2^j -1中值最小的一个值(从i开始2^j个数)  
  7. //dp[i][j] = min( dp[i][j-1], dp[i+2^(j-1)][j-1] );  
  8. //查询RMQ( i, j )  
  9. //将i,j分成两个2^k个区间  
  10. //k = log2( j - i + 1 )  
  11. //查询结果 min( dp[i][k], dp[j-2^k+1][k] )  
  12. int dp[MAX][MAX];  
  13.   
  14. inline int Min( int x, int y )  
  15. {  
  16.     return x < y ? x : y;  
  17. }  
  18.   
  19. //使用DP,建立查询表  
  20. void MakeRmqIndex( int *data, int size )  
  21. {  
  22.     int i, j;  
  23.     for( i=0; i<size; i++ )  
  24.     {  
  25.         dp[i][0] = i;  
  26.     }  
  27.     for( j=1; (1<<j)<size; j++ )  
  28.     {  
  29.         for( i=0; i+(1<<j)-1 < size; i++ )  
  30.         {  
  31.             dp[i][j] = data[ dp[i][j-1] ] < data[ dp[i+(1<<(j-1))][j-1] ] ? dp[i][j-1] : dp[i+(1<<(j-1))][j-1];   
  32.         }  
  33.     }  
  34. }  
  35.   
  36. //查表,并返回结果  
  37. int RmqIndex( int begin, int end, int *data )  
  38. {  
  39.     int k = (int)( log( ( end - begin + 1 ) * 1.0 )/ log( 2.0 ) );  
  40.     return data[ dp[begin][k] ] < data[ dp[end-(1<<k)+1][k] ] ? dp[begin][k] : dp[end-(1<<k)+1][k];  
  41. }  
  42.   
  43. int main()  
  44. {     
  45.     int data[10] = { 1, 3, 3, 4, 5, 6, 6, 7, 9, 11 };     
  46.   
  47.     //返回最小索引  
  48.     MakeRmqIndex( data, 10 );  
  49.     cout << RmqIndex( 4, 9, data) << endl;    
  50.     return 0;  
  51. }  

15.一棵排序二叉树,令f=(最大值+最小值)/2,设计一个算法,找出距离f值最近、大于f值的结点。复杂度如果是O(n2)则不得分。

 

16. 一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。复杂度最好是O(n),如果是O(n2)则不得分 

这题要求O(n),我能想到就是:使用一个有N个元素的数组,然后用数值作为数组的下标,然后遍历数组。


1.正整数序列Q中的每个元素都至少能被正整数a和b中的一个整除,现给定a和b,需要计算出Q中的前几项,

例如,当a=3,b=5,N=6时,序列为3,5,6,9,10,12

(1)、设计一个函数void generate(int a,int b,int N ,int * Q)计算Q的前几项

(2)、设计测试数据来验证函数程序在各种输入下的正确性。

 

感觉有点类似归并排序的Merge。有两个数组A、B。

数组A存放:3*1、3*2、3*3…

数组B存放:5*1、5*2、5*3…

有两个指针 i, j,分别指向A、B的第一个元素。取Min( A[i], B[j] ),并将较小值的指针前移,然后继续比较。

当然,编程实现的时候,完全没有必要申请两个数组,用两个变量就可以。

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. void Generate( int a,int b,int N ,int * Q )  
  5. {     
  6.     int tmpA, tmpB;  
  7.     int i = 1;  
  8.     int j = 1;  
  9.   
  10.     for( int k=0; k<N; k++ )  
  11.     {  
  12.         tmpA = a * i;  
  13.         tmpB = b * j;  
  14.   
  15.         if( tmpA <= tmpB )  
  16.         {  
  17.             Q[k] = tmpA;  
  18.             i++;  
  19.         }  
  20.         else  
  21.         {  
  22.             Q[k] = tmpB;  
  23.             j++;  
  24.         }  
  25.     }  
  26. }  
  27.   
  28. int main()  
  29. {  
  30.     int Q[6];  
  31.     Generate( 3, 5, 6 ,Q );  
  32.     return 0;  
  33. }  

2.有一个由大小写组成的字符串,现在需要对他进行修改,将其中的所有小写字母排在大写字母的前面(大写或小写字母之间不要求保持原来次序),如有可能尽量选择时间和空间效率高的算法c语言函数原型void proc(char *str)

也可以采用你自己熟悉的语言

 

应该类似快排的partition。快排的partition也有两种常见的实现:从左往右扫描、从两头往中间扫描。这里使用从左往后扫描的方式。

字符串在调整的过程中可以分成两个部分:已排好的小写字母部分、待调整的剩余部分。用两个指针i和j,其中i指向待调整的剩余部分的第一个元素,用j指针遍历待调整的部分。当j指向一个小写字母时,交换i和j所指的元素。向前移动i、j,直到字符串末尾。

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. void Proc( char *str )  
  5. {  
  6.     int i = 0;  
  7.     int j = 0;  
  8.   
  9.     //移动指针i, 使其指向第一个大写字母  
  10.     while( str[i] != '\0' && str[i] >= 'a' && str[i] <= 'z' ) i++;  
  11.   
  12.     if( str[i] != '\0' )  
  13.     {  
  14.         //指针j遍历未处理的部分,找到第一个小写字母       
  15.         for( j=i; str[j] != '\0'; j++ )  
  16.         {  
  17.             if( str[j] >= 'a' && str[j] <= 'z' )  
  18.             {  
  19.                 char tmp = str[i];  
  20.                 str[i] = str[j];  
  21.                 str[j] = tmp;  
  22.                 i++;                  
  23.             }             
  24.         }  
  25.     }     
  26. }  
  27.   
  28. int main()  
  29. {  
  30.     char data[] = "SONGjianGoodBest";  
  31.     Proc( data );     
  32.     return 0;  
  33. }  

 3.如何随机选取1000个关键字。

给定一个数据流,其中包含无穷尽的搜索关键字(比如,人们在谷歌搜索时不断输入的关键字)。如何才能从这个无穷尽的流中随机的选取1000个关键字?

 

说实话我不会做,是看网上的答案。感觉是对的,但又说不上为什么。

思路是这样的:

1.申请一个1000个元素的数组,用于保存最后选中的关键字

2.将数据流中前1000个直接放入数组中

3.对于第n个元素(n>1000), 以1000/n的概率随机替换数组中的一个元素

这个就能保证每个元素都以1000/n的概率被选中。哎,为什么?先放这吧,以后再说。 

4.判断一个自然数是否是某个数的平方。说明:当然不能使用开方运算。 

也就是判断一个自然数是否是完全平方数。

方法一:从1开始逐个尝试,即判断1*1,2*2,3*3…,算法复杂度O( N^0.5 )

方法二:相当于在1…N之间找一个数x,使x*x = N。这样看就是一个查找问题,所以用折半查找。算法复杂度O( logN )。

方法三:使用完全平方数的性质:每个完全平方数都可以表示成一系列奇数的和。

不妨这样简单理解一下:

设x是一个完全平方数,即 x = a^2,所以

a^2 = ( a – 1 +1 )^2 = (a-1)^2 + 2( a – 1 ) + 1

               =( (a-2) + 1 )^2 + 2( a – 1 ) + 1

               =(a-2)^2 + ( 2( a – 2 ) + 1 ) + (2( a – 1 ) + 1 )

即 x = 1 + 3 + 5 + … + (2( a – 1 ) + 1 )

故x可以表示为一系列奇数的和. 

因此判断完全平方数的算法:x – 1 – 3 – 5…即从x中连续不断的减去一个奇数,如果结果可以为0,则x是完全平方数。否则,不是。算法复杂度O(N ),当然由于这里做的全部是减法,可能也回比较快。

5.给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数。 

关键是要保证每个数字产生的概率相等。

把能随机生成整数1到5的函数记为R15。

我的想法是:把R15调用6次,然后统计这6次中,某个数字出现的次数。比如,统计1出现的次数。1的次数[0, 6],然后给次数加一,就可以随机生成1到7之间的整数。

网上的解法:首先,调用7次R15。然后,取最大值对应的下标,由这些值构成了一个新数组。然后继续调用R15,直到最后只剩下一个数字。

{ 1,2,3,4,5,6,7 }

 5,3,1,5,2,4,5

{ 1, , ,4, , ,7 }

 4, , ,1, , ,3

{ 1 } 

6.1024! 末尾有多少个? 

求末尾0个数,也就是对1024!进行因子分解,求因子中10的个数。在进一步,因子中10的个数,就相当与质因子中2*5的个数。因为质因子5的个数比2少,所以也就是求1024!中质因子5的个数。

1,2,3,…,1024中哪些数都含有质因子5?主要有以下几类:

第一类:5的倍数,1024/5 = 204个

第二类:25的倍数,1024/25 = 40个

第三类:125的倍数,1024/125 = 8个

第四类:625的倍数,1024/625 = 1个

则,总的因子5的个数:204 + 40 + 8 + 1 = 253

当然,为什么加起来就是最后的答案?这个不难,自己想想吧。 

7. 有个海盗,按照等级从5到1排列,最大的海盗有权提议他们如何分享枚金币。

但其他人要对此表决,如果多数反对,那他就会被杀死。

他应该提出怎样的方案,既让自己拿到尽可能多的金币又不会被杀死?

(提示:有一个海盗能拿到98%的金币)

 

      很有意思的一个题。嘿嘿,不会做,也还是看网上答案的。

      当有5个人时,等级为5的海盗,等级最高,他来分配。分配时要考虑两个问题:利益最大、不被杀死。至于他的分配方案会不会招来杀身之祸,完全取决于其他4个人的反应。所以考虑,4个人的情况。

      当有4个人时,等级为4的海盗,等级最高,他来分配。至于他的分配方案会不会招来杀身之祸,完全取决于其他3个人的反应。所以考虑,3个人的情况。

…

       当有2个人时,等级为2的海盗,等级最高,他来分配。这时他就可以肆无忌惮的分配了。分配方案:100,0。即给自己100枚金币,给等级为1的海盗0枚金币。虽然对等级为1的海盗来说很不公平,但是他反对也没用,因为只有两个人,他占不了大多数。

       再来考虑三个人的问题。当有3个人时,等级为3的海盗,等级最高,他来分配。他只要在前两个人中争取一个人就行。分配方案:99,0,1。这样等级为1的海盗肯定不会反对,因为比2个人的时候分的多。只有等级为2的海盗反对,但是没有用

考虑四个人的情况。分配方案:99,0,1,0。等级为4、2的海盗满意。

五个人的情况。分配方案:98,0,1,0,1。

8.给定一个集合A=[0,1,3,8](该集合中的元素都是在,之间的数字,但未必全部包含),指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。

比如,A=[1,0] K=21 那么输出结构应该为100。

 

首先,计算正整数K的位数。假设k有m位。把用A中的元素组成一个大于K的最小正整数记为x。那么x就有m位或者m+1位。

根据K的最高位,在A中选数字。分两种情况:A中的数字都比k的最高位小、A中至少有一个数字等于大于k的最高位。

1.A中的数字都比k的最高位小,则x有m+1位。这时,只要用A中的数字组成一个m+1位的最小正整数即可。

2.A中至少有一个数字等于大于k的最高位。这时x的最高位就是不小于K最高位的最小数字。然后,用同样的方法继续比较下一位。

编程实现:很烦,写的都想吐血了。

[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <algorithm>  
  3. using namespace std;  
  4.   
  5. //target为int值,最多是10位数  
  6. const int MAX_INT_CNT = 20;  
  7.   
  8. int NearestInt( int target, int *data, int size )  
  9. {     
  10.     int ans = 0;  
  11.       
  12.     //计算target的位数  
  13.     int cnt = 0;      
  14.     int tmp = target;  
  15.     while( tmp > 0 )   
  16.     {  
  17.         cnt++;  
  18.         tmp /= 10;  
  19.     }  
  20.   
  21.     //将target转换为字符串  
  22.     char des[MAX_INT_CNT];  
  23.     itoa( target, des , 10 );  
  24.     string strTarget( des );  
  25.   
  26.     //对数组排序  
  27.     sort( data, data+size );  
  28.   
  29.     int flag = 0;     
  30.     int i, j;  
  31.     for( i=0; i<cnt; i++ )  
  32.     {  
  33.         ans *= 10;  
  34.         //遍历数组,找到一个合适的元素  
  35.         for( j=0; j<size && flag==0; j++ )  
  36.         {  
  37.             if( strTarget[i] == data[j] )  
  38.             {                             
  39.                 ans += data[j];  
  40.                 break;                                            
  41.             }  
  42.             if( strTarget[i] < data[j] )  
  43.             {  
  44.                 ans += data[j];  
  45.                 flag = 1;  
  46.                 break;  
  47.             }  
  48.         }  
  49.         if( j >= size ) flag = 2;  
  50.         //flag == 2表示前面的数字都相等,只要后面的多一位就行  
  51.         if( flag == 2 )  
  52.         {  
  53.             if( i == 0 )  
  54.             {  
  55.                 //找到一个非0元素  
  56.                 for( j=0; j<size; j++ )  
  57.                 {  
  58.                     if( data[j] > 0 )break;   
  59.                 }                 
  60.                 ans += data[j];  
  61.             }  
  62.             else   
  63.                 ans += data[0];  
  64.         }         
  65.         //flag == 1表示前面的数字比较大,后面的取最小的数字即可         
  66.         if( flag == 1 ) ans += data[0];   
  67.     }  
  68.     //如果前面的数字都相等  
  69.     if( flag == 2 )  
  70.     {  
  71.         ans *= 10;  
  72.         ans += data[0];  
  73.     }     
  74.     return ans;  
  75. }  
  76.   
  77.   
  78. int main()  
  79. {  
  80.     int data[] = { 0, 1, 3, 8 };  
  81.       
  82.     cout << NearestInt( 21, data, 4 ) << endl;  
  83.     return 0;  
  84. }  

9. 用C语言实现一个revert函数,它的功能是将输入的字符串在原串上倒序后返回。 

基本的字符串操作。应该没有什么问题,比起链表的反转简单多了。

[cpp]  view plain copy
  1. char* Revert( char *str )  
  2. {  
  3.     if( str != NULL )  
  4.     {  
  5.         char *begin = str;  
  6.         char *end = str;  
  7.         while( *end != '\0' ) end++;  
  8.         end--;  
  9.   
  10.         while( begin != end )  
  11.         {  
  12.             char tmp = *begin;  
  13.             *begin = *end;  
  14.             *end = tmp;  
  15.   
  16.             begin++;  
  17.             end--;  
  18.         }  
  19.     }  
  20.     return str;  
  21. }  

10.用C语言实现函数void * memmove(void*dest, const void *src, size_t n)。memmove函数的功能是拷贝src所指的内存内容前n个字节到dest所指的地址上。 


其实就是自己写一个memcpy函数。注意下面三种情况:

指针为空

两个指针间距过小( 如dest = 10010, src =10020, n = 20 )

void*的转换

[cpp]  view plain copy
  1. void* Memmove( void *dest, const void *src, size_t n )  
  2. {  
  3.     char *cDest = (char*) dest;  
  4.     char *cSrc = (char*) src;  
  5.       
  6.     assert( cDest != NULL && cSrc != NULL );  
  7.     assert( cDest >= cSrc + n || cSrc >= cDest + n );  
  8.   
  9.     while( n-- )    *cDest++ = *cSrc++;   
  10.     return dest;      
  11. }  

11.有一根厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。木杆很细,同时只能通过一只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。

编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间。

 

        不知这题是想考什么。

        题目的难点在于:初始状态,蚂蚁的方向任意。因为只有5个蚂蚁,每只蚂蚁的方向只有左、右两种选择,因此5只蚂蚁的初始方向有2^5 = 32种情况。

        没有想到什么好的算法,只能枚举所有情况。对每种情况,模拟蚂蚁的爬杆过程:沿初始方向前进、每秒更新一次蚂蚁的位置、更新完成后进行碰撞检测。当所有蚂蚁都爬出细杆后,就可以得到所需时间。最后,在所有的初始情况下,求最小时间和最大时间。索性数据量很小,时间可以接受。

[cpp]  view plain copy
  1. const int LEFT = 0;  
  2. const int RIGHT = 1;  
  3.   
  4. //记录每个蚂蚁的初始方向  
  5. int dir[5];  
  6. //记录每个蚂蚁的初始位置  
  7. int pos[5];  
  8. //记录每个蚂蚁是否爬出了细杆  
  9. bool isFinish[5];  
  10.   
  11. void Init( int  i )  
  12. {  
  13.     //初始化蚂蚁的方向  
  14.     int tmp = i;  
  15.     int mask = 0x0001;  
  16.     for( int j=0; j<5; j++ )  
  17.     {  
  18.         dir[j] = ( tmp & mask ) ? RIGHT : LEFT;  
  19.         tmp >>= 1;          
  20.     }  
  21.   
  22.     //初始化蚂蚁的位置  
  23.     pos[0] = 3;  
  24.     pos[1] = 7;  
  25.     pos[2] = 11;  
  26.     pos[3] = 17;  
  27.     pos[4] = 23;  
  28.   
  29.     //初始化蚂蚁的状态标志  
  30.     memset( isFinish, false, sizeof(isFinish) );  
  31. }  
  32.   
  33. void AntTime( int &maxTime, int &minTime )  
  34. {  
  35.     int max = 0;  
  36.     int min = 10000000;  
  37.   
  38.     //依次处理32种情况  
  39.     for( int i=0; i<32; i++ )  
  40.     {  
  41.         Init( i );    
  42.   
  43.         //记录已经爬出细杆的蚂蚁个数  
  44.         int cnt = 0;  
  45.   
  46.         //每秒检测一次  
  47.         int time;         
  48.         for( time=1; ; time++ )  
  49.         {  
  50.             //更新蚂蚁位置  
  51.             for( int j=0; j<5; j++ )  
  52.             {  
  53.                 if( !isFinish[j] )  
  54.                 {  
  55.                     if( dir[j] == LEFT )  
  56.                         pos[j]--;  
  57.                     else  
  58.                         pos[j]++;  
  59.                 }                 
  60.             }  
  61.               
  62.             //检测蚂蚁是否已爬出细杆  
  63.             for( int m=0; m<5; m++ )  
  64.             {  
  65.                 if( !isFinish[m] && ( pos[m] < 0 || pos[m] > 23 ) )  
  66.                 {  
  67.                     isFinish[m] = true;  
  68.                     cnt++;  
  69.                 }  
  70.             }  
  71.   
  72.             //如果所有的蚂蚁都已经爬出细杆,则跳出  
  73.             if( cnt >= 5 ) break;              
  74.               
  75.             //如果相撞,则掉头  
  76.             for( int k=0; k<5; k++ )  
  77.             {  
  78.                 if( !isFinish[k] )  
  79.                 {  
  80.                     if( ( k == 0 && pos[k] == pos[k+1] ) || ( k == 5 && pos[k] == pos[k-1] ) ||  
  81.                         ( ( k > 0 && k < 5 ) && ( pos[k] == pos[k+1] || pos[k] == pos[k-1] ) )  
  82.                       )  
  83.                     {  
  84.                         dir[k] = ( dir == LEFT ) ? RIGHT : LEFT;  
  85.                     }  
  86.                 }                                 
  87.             }  
  88.         }  
  89.   
  90.         if( time > max ) max = time;  
  91.         if( time < min ) min = time;  
  92.     }  
  93.     maxTime = max;  
  94.     minTime = min;  
  95. }  

12.请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句 

这里有两种做法:正数的绝对值等于本身、两数相减判断符号位 

[cpp]  view plain copy
  1. #define MAX( a, b ) ( fabs( a, b ) == ( (a) - (b) ) ? (a) : (b) )  
  2. #define MMAX( a, b ) ( ( ( (a) - (b) ) & ( 1 << 31 ) ) ? (a) : (b) )  

13.两个数相乘,小数点后位数没有限制,请写一个高精度算法

 

14.有A、B、C、D四个人,要在夜里过一座桥。他们通过这座桥分别需要耗时1、2、5、10分钟,只有一支手电,并且同时最多只能两个人一起过桥。请问,如何安排,能够在17分钟内这四个人都过桥?

 

        这题想想不难,就不知道具体编程应该怎么实现,能想到的就是DFS。这里的17分钟应该就是最短时间了。先不管编程实现了,说说具体的思路吧

首先,要到对岸,每次不能只过一个人。因为这个人拿了手电,其他人都过不了。这样,每次过桥,必须两个人。两个人过去,其中一个人再拿了手电回来。那选哪两个人过去,哪个人再回来?当然是时间最小的啦。所以,5分钟的人和10分钟的人结伴过河,这样可以把5分钟的时间淹没在10分钟内,共需10钟就可以完成。在让时间最小的人拿了手电回去,那自然选1分钟的人了。也就是说,1分钟的人必须在5、10之前到达对岸。

         这样,整个过程就是:1、2先到对岸(2Min),2拿了手电返回(2Min),5、10再结伴过桥(10Min),1拿手电返回(1Min),最后1、2结伴过桥(2Min),总共刚好17分钟。 

15.有12个小球,外形相同,其中一个小球的质量与其他11个不同,给一个天平,问如何用3次把这个小球找出来,并且求出这个小球是比其他的轻还是重

 

        很久以前的题了,估计大多数人都见过。类似折半查找的方法,把问题的规模以O( lgn )的速度减小。12---6---3---1。当剩3个时,问题最精妙,这时有三种状态可利用:天平左半、天平右边、不在天平两端。这提示我们,其实27个小桥也可以用这个方法。27---9----3----1,即称3次就可以完成。

        其实,这里可以总结一个规律:( 3^(n-1), 3^n ]内的数都只需n次就可以完成。即,10、11、12、….、27个球都只用3次就可以。

16.在一个文件中有10G 个整数,乱序排列,要求找出中位数。内存限制为2G。只写出思路即可。 

       海量数据处理的问题。10G个数,中位数就是第5G、第5G+1个数。回想一下,一般情况下求中位数的做法:类似于快排的partition,找到一个数,使比它小的数的个数占到总数的一半就行。所以,可以把数值空间分段,然后统计每一段中数据的个数,这样就可以很容易的确定中位数在那一段。找个该段后,数据量已经急剧减小了,剩下的问题就好处理了。这种方法可以说是桶排序的思想,也可以说是hash的思想。下面具体分析一下:

        因为要统计每一段中数据的个数,所以可以用一个unsigned int型。unsigned int一般占4个字节,可以计数到2^32-1,大约是4G。题目中有10G个数,如果有很多数落在同一个段中,unsigned int肯定不够用。所以,这里的计数用要8字节的long long。即,相当于有一个数组,数组是long long性,数组的每一个元素,代表了一个数据段内的数据个数。这个数组有多大?为了充分利用2G内存,数组大小2G/8 = 256M。即,有数组long long cnt[256M].

        假设题目中的10G个数都是4字节的int。如何把这10G个整数,映射到cnt[256M]的数组中。可以使用计算机中的虚拟地址到物理地址的转换。取int的高28位作为数组下标的索引值,这样就可以完成映射。

整个算法的流程:

扫描10G个整数,对每个整数,取高28位,映射到数组的某个元素上

给数组的这个元素加1,表示找到一个属于该数据段的元素

扫描完10G个整数后,数组cnt中就记录了每段中元素的个数

从第一段开始,将元素个数累计,直到值刚好小于5G,则中位数就在该段

这时对10G个整数再扫描一遍,记录该段中每个元素的个数。直至累计到5G即可。 

17..一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数 

方法一:

使用位图。4字节的int,有4G个不同的值。每个值,对应1bit,则共需4G/8 = 512M

内存。初始状态,对512M的位图清零。然后,对这40亿个整数进行统计。如果某个值出现了,那么就把这个值对应的bit置位。最后,扫描位图,找到一个没有被置位的bit即可。

方法二:

分段统计。Long long cnt[512M/8=64M]对应数值空间的64M个数据段。每个数据段包含64个不同值,用一个long long作为这个数据段内的位图,位图占64M*8=512M。

这样扫描一遍40亿个整数后,从数组中找到一个计数小于64的元素,然后查看它的位图,找出未出现的元素。

方法二平均性能应该比方法一快,但它占的内存很恐怖。其实,这两种方法都不是很实际,总共1G的内存,算法就消耗512M甚至1G,那剩下的系统程序怎么办?OS都跑不起来了吧。 

18.腾讯服务器每秒有2w个QQ号同时上线,找出5min内重新登入的qq号并打印出来。

        这应该是道面试题,面试官随口问了一下。主要是看思路吧。

        最简单的想法:直接用STL的set。从某一时刻开始计时,每登陆一个QQ,把它放入set,如果已存则直接打印。直到5min后,就可以over了。下面来简单分析一下算法的负复杂度:

空间复制度:用str存储每个QQ号,假设QQ号有20位,理想情况下每个QQ占20Byte。则5min内的QQ:2w * 60 * 5 = 600w个,需要的存储空间600w * 20byte = 12000w byte = 120M,这样的存储应该可以忍受吧。

时间复杂度:STL的set是用二叉树(更确切的说是:红黑树)实现的,查找效率是O( lgn ),应该还是挺快的吧。

 

        呃,有人说不让用STL。那就自己设计一个数据结构呗。该用什么数据结构呢?想了想,还是继续用树,这里用一个trie tree吧。节点内容包括QQ号、指向子节点的指针(这里有10个,认为QQ由0---9的数字组成)。登陆时间要不要?考虑这样一个问题:是否需要把所有的QQ都保存在内存中?随着时间的增加,登陆的QQ会越来越多,比较好的方法是把长时间不登陆的QQ释放掉。所以需要记录登陆时间,以便于释放长期不登陆的QQ。

[cpp]  view plain copy
  1. struct TrieNode  
  2. {  
  3.     string qq;  
  4.     int lastLoginTime;  
  5.     TrieNode *next[10];  
  6. };  

我们的trie上的操作主要有两个:查找并插入、删除。也就是说,这颗树是不断动态变化的,我们需要维护它。

 

【2023】华为OD机试真题Java-题目0203-统计差异值大于相似值二元组个数 题目描述: 对于任意两个正整数A和B,定义它们之间的差异值和相似值:AB转换成二进制后,对于二进制的每一位,对应位置的bit值不相同则为1,否则为0;AB转换成二进制后,对于二进制的每一位,对应位置的bit值都为1则为1,否则为0;现在有n个正整数A0​到An−1​,问有多少对ij0≤ijnAi​和Aj​的差异值大于相似值。假设A5B3;则A的二进制表示101;B的二进制表示011;则A与B的差异值二进制为。 阅读详情

相关推荐

LightTools 中LCD投影仿真的checkerboard pattern偏振控制技术解析

本文深入解析了在LightTools软件中进行LCD投影仿真时,利用checkerboard pattern(棋盘格图案)结合偏振控制技术来模拟液晶面板像素开关、提升图像对比度的核心方法。文章从实战角度出发,详细拆解了通过设置波片(如1/2波片)和偏振片来操控S光与P光转换的原理,并分享了在LightTools中搭建仿真模型、使用VBA脚本自动化配置参数以提高效率的实用技巧,为光学工程师优化投影系统仿真流程提供了清晰指导。

weixin_29305313的博客 344

UNIX再学习 -- 死磕内存管理

malloc/free简化实现;malloc 和 sbrk 关系;虚拟内存机制。 一个内存管理 C 语言部分讲,UNIX部分讲,Linux部分还讲,死磕到底!!一、mallc/free简化实现上篇文章已经讲解了动态内存分配/释放函数,参看:UNIX再学习 – 内存管理 下面来讲一下,它的自定义函数实现,其中有三个部分:1、内存控制块内存控制块用于管理每次分配的内存块,记录该内存块的字节大小、忙闲状

不积跬步,无以至千里 4149

【论文导读】ICDM2018|SASRec---基于自注意力机制的序列推荐(召回)

前言本次分享2018年发表在ICDM上的论文----「Self-Attentive Sequential Recommendation」。主要是应用self-attention机制来做一...

Blank_Space 8033

C/C++通用内存分配器原理解析

C/C++分配器存在的问题 1、分配速度慢,通常用于为大型对象(数百个或数千个bytes)分配内存 2、存在一个管理内存的记忆池,常会耗用一部分内存资源,对于new分得得每一块内存,都会对其进行登记,而登记所需内存达4~32个bytes,对于分配小型对象,用于登记所需内存占比大,不适合用于分配小型对象的内存。 内存分配器的工作方式 内存分配器管理一个由raw bytes所组成的内存池,能够从池中分配任意大小的内存区块。 管理内存需要的簿记结构,内存控制块: struct MemControlBlock {

xunye的博客 1577

保姆级教程:用Adams/Car和Simulink搞定你的第一个整车联合仿真(附模型文件)

本文提供了一份详尽的Adams/Car与Simulink联合仿真教程,涵盖从环境配置到模型导出的全流程。通过实战案例解析,帮助工程师快速掌握多体动力学仿真与控制算法开发的集成技术,特别适合汽车工程领域的初学者。文章还包含常见问题解决方案和性能优化建议,助您高效完成整车联合仿真项目。

weixin_29663861的博客 337

ROS1集群通信的可靠升级方案:为什么在无线环境下我选择了swarm_ros_bridge而非原生DDS

本文探讨了ROS1集群通信在无线环境下的可靠升级方案,重点分析了swarm_ros_bridge相较于原生DDS的优势。通过实际案例和性能对比,展示了ZeroMQ在无线通信中的稳定性和高效性,特别适合无人机编队和移动机器人集群等场景。

weixin_42567279的博客 386

ucos-II学习之:数据结构(任务控制块/事件控制块/内存控制块总结一)

ucos-II学习之:数据结构(任务控制块/事件控制块/内存控制块总结一)

sz189981的博客 3293

IC芯片验证 - 手把手教你搭建UVM验证环境

这是一个UVM的demo项目

howard789的博客 3万+

【转】经典面试题

转自:http://blog.youkuaiyun.com/fanzitao/article/details/7930801  字符串转化为数字 注意:处理正负号,可以处理正负号,字母打头,-+打头,以及其中字符串中间含有非法字符的情况。 bool change(char *str,int &amp;num) { num = 0; int mul = 1; if...

Hello world. 227

实战:如何用MIPI CSI-2高效传输RAW10图像数据(附带宽优化技巧)

本文深入探讨了MIPI CSI-2协议在RAW10图像数据传输中的高效应用,详细解析了4像素5字节打包机制及其带宽优化技巧。通过动态Lane分配、位深度自适应压缩和虚拟通道交错传输等实战方法,显著提升传输效率,适用于IoT摄像头开发等低功耗场景。

css33的专栏 731

ros1 ubuntu22.04 安装教程

ROS1 ubuntu22.04 安装教程

autolabor的博客 9196

数据结构经典面试题(转)

链表经典面试题

今天是个好天气~ 646

ICP-10111气压传感器原理图设计,已量产(压力传感器)

在最近的室内导航定位项目中,我们需要一款能捕捉厘米级垂直高度变化的气压传感器 —— 毕竟室内环境里,哪怕是单个台阶的高度差都得精准识别。对比了几款器件后,最终选定了 ICP-10111:它 ±1Pa 的压差精度刚好能把高度差分辨到 8.5cm,0.4Pa 的低压力噪声能让数据输出足够稳定,再加上 0.5Pa/℃的低温漂特性,长期工作的可靠性也能满足需求。下面聊聊这套适配 ICP-10111 的硬件电路设计细节。

不脱发的程序猿 333

(转)算法经典面试题整理

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;算法经典面试题整理(java实现) 以下从Java角度解释面试常见的算法和数据结构:字符串,链表,树,图,排序,递归 vs. 迭代,动态规划,

qq_16264655的博客 410

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

MySQL经典面试题(转)

1、MySQL的复制原理以及流程 (1)、复制基本原理流程 1. 主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中; 2. 从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进 自己的relay log中; 3. 从:sql执行线程——执行relay log中的语句; (2)、MySQL复制的线程...

Marmara 3万+

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

【转】MySQL经典面试题

MySQL 经典 38 问! 事务的四大特性? 事务隔离级别有哪些? 索引 什么是索引? 索引的优缺点? 索引的作用? 什么情况下需要建索引? 什么情况下不建索引? 索引的数据结构 Hash 索引和 B+ 树索引的区别? 为什么 B+ 树比 B 树更适合实现数据库索引? 索引有什么分类? 什么是最左匹配原则? 什么是聚集索引? 什么是覆盖索引? 索引的设计原则? 索引什么时候会失效? 什么是前缀索引? 常见的存储引擎有哪些? MyISAM 和 InnoDB 的区别? MVCC 实现原理? 快照读和当前

yunxixiao的博客 201

[转]PHP经典面试题50道

<!--v/:* {behavior:url(#default#VML);}o/:* {behavior:url(#default#VML);}w/:* {behavior:url(#default#VML);}.shape {behavior:url(#default#VML);}--> Normal 0 7.8 磅 0 2

aidenliu的专栏 1103

iOS经典面试题(转)

iOS经典面试题 前言 写这篇文章的目的是因为前两天同学想应聘iOS开发,从网上找了iOS面试题和答案让我帮忙看看。我扫了一眼,倒吸了一口冷气,仔细一看,气的发抖。整篇题目30多个没有一个答案是对的,总结这篇面试题的作者对iOS机制根本就是一知半解就敢发到网上,不管有心还是无心都是坑害新人。所以在这里总结一下这几年面试别人和被别人面试遇到的一些我认为比较好的基础题目分享给大家,进阶题目在后续...

SharkArmy 63

【转】 iOS经典面试题

原文地址:http://blog.cocoachina.com/article/13706 前言 写这篇文章的目的是因为前两天同学想应聘iOS开发,从网上找了iOS面试题和答案让我帮忙看看。我扫了一眼,倒吸了一口冷气,仔细一看,气的发抖。整篇题目30多个没有一个答案是对的,总结这篇面试题的作者对iOS机制根本就是一知半解就敢发到网上,不管有心还是无心都是坑害新人。所以在这里总结一下这几年

lin1109221208的博客 626

(转)微软101道经典面试题

1. Given a rectangular (cuboidal for the puritans) cake with a rectangular piece removed (any size or orientation), how would you cut the remainder of the cake into two equal halves with one straight 

LoocalVinci的专栏 2136

jQuery经典面试题及答案精选(转)

jQuery是一款非常流行的Javascript框架,如果你想要从事Web前端开发这个岗位,那么jQuery是你必须掌握而且能够熟练应用的一门技术。本文整理了一些关于jQuery的经典面试题及答案,分享给正要面试Web开发岗位的同学。 问题:jQuery的美元符号$有什么作用? 回答:其实美元符号$只是”jQuery”的别名,它是jQuery的选择器,如下代码: $(document)....

weixin_30378623的博客 95

16道经典嵌入式C语言面试题(转)

16道经典嵌入式C语言面试题1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在这想看到几件事情: 1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等) 2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年

年少辉煌的专栏 1045

经典面试题【转】

面试过程中,面试官会向应聘者发问,而应聘者的回答将成为面试官考虑是否接受他的重要依据。对应聘者而言,了解这些问题背后的“猫腻”至关重要。本文对面试中经常出现的一些典型问题进行了整理,并给出相应的回答思路和参考答案。读者无需过分关注分析的细节,关键是要从这些分析中“悟”出面试的规律及回答问题的思维方式,达到“活学活用”。   问题一:“请你自我介绍一下”   思路:1、这是面试的必考...

mohaiyong的专栏 107
上一篇: 常量指针和指针常量
下一篇: [面试题] 求数组两两之差绝对值最小的值
cjbbx
博客等级 码龄16年 12粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值