面试算法

1、给一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么b是a的兄弟单词,比如的单词army和mary互为兄弟单词。
解:
a,将a-z对应成从2开始的26个素数,然后只需要比较两个单词的字母乘积是否相等即可。
b,字典树的典型应用,一般情况下,字典树的结构都是采用26叉树进行组织的,每个节点对应一个字母,查找的时候,就是一个字母一个字母的进行匹配,算法的时间复杂度就是单词的长度n,效率很高。因此这个题目可以定义一个字典树作为数据结构来查询的,时间效率会很高,这样就转化为在一棵字典树中查找兄弟单词,只要在字典树中的前缀中在存储一个vector结构的容器,这样查找起来就是常数级的时间复杂度了,效率很高的。
    数据结构可以定义如下:
typedef struct word  
{    
    vector<string> brother;    // 用于保存每个单词的兄弟单词  
    word *next[26];            // 字典树中每个节点代表一个字符,并指向下一个字符  
};  
如上述数据结构所示,字典树的建立是在预处理阶段完成的,首先根据字典中的单词来建立字典树,建立的时候,需要稍微特殊处理一下,就是比如pots、stop和tops互为兄弟单词,那么在字典中按照首字母顺序的话,应该先遇到pots单词,那么我首先对其进行排序,结果是opts,那么字典树中就分别建立4个节点,分别为o->p->t->s,当然这个是不同层次的,在节点s处的vector容器brother中添加单词pots,遇到stop的时候,同样的方法,排序是opts,此时发现这4个节点已经建立了,那么只需要在第四个节点s处的vector容器brother中添加单词stop,tops单词的处理方法是同样的。
     这样建立完字典树后,查询兄弟单词的效率就会很高了,比哈希的效率还要高;查到tops的兄弟的单词的时候,首先排序,那么就是opts,然后在字典树中查找opts,在s处将其vector容器brother中的的单词输出就是tops的所有兄弟单词。
http://blog.csdn.net/hackbuteer1/article/details/7542774




2、假设现在我们面临这样一个问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?
解:
a,如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有:
如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;
如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯, j 被置为0。
int ViolentMatch(char* s, char* p)  
{  
    int sLen = strlen(s);  
    int pLen = strlen(p);  
  
    int i = 0;  
    int j = 0;  
    while (i < sLen && j < pLen)  
    {  
        if (s[i] == p[j])  
        {  
            //①如果当前字符匹配成功(即S[i] == P[j]),则i++,j++      
            i++;  
            j++;  
        }  
        else  
        {  
            //②如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0      
            i = i - j + 1;  
            j = 0;  
        }  
    }  
    //匹配成功,返回模式串p在文本串s中的位置,否则返回-1  
    if (j == pLen)  
        return i - j;  
    else  
        return -1;  
}  




3、strcpy函数的实现
解:
a,
char *my_strcpy(char *dst,const char *src)  
{  
    assert(dst != NULL);  
    assert(src != NULL);  
    char *ret = dst;  
    while((* dst++ = * src++) != '\0')   
        ;  
    return ret;  
}  
b,
假如考虑dst和src内存重叠的情况,strcpy该怎么实现


char s[10]="hello";


strcpy(s, s+1); //应返回ello,


//strcpy(s+1, s); //应返回hhello,但实际会报错,因为dst与src重叠了,把'\0'覆盖了


所谓重叠,就是src未处理的部分已经被dst给覆盖了,只有一种情况:src<=dst<=src+strlen(src)


C函数memcpy自带内存重叠检测功能,下面给出memcpy的实现my_memcpy。
char * strcpy(char *dst,const char *src)
{
    assert(dst != NULL && src != NULL);


    char *ret = dst;


    my_memcpy(dst, src, strlen(src)+1);


    return ret;
}
char *my_memcpy(char *dst, const char* src, int cnt)
{
    assert(dst != NULL && src != NULL);


    char *ret = dst; 


    if (dst >= src && dst <= src+cnt-1) //内存重叠,从高地址开始复制
    {
        dst = dst+cnt-1;
        src = src+cnt-1;
        while (cnt--)
            *dst-- = *src--;
    }
    else    //正常情况,从低地址开始复制
    {
        while (cnt--)
            *dst++ = *src++;
    }
    
    return ret;
}




4.处理海量数据问题之六把密匙
密匙一、分而治之/Hash映射 + Hash_map统计 + 堆/快速/归并排序




5.非常大的文件,装不进内存。每行一个int类型数据,现在要你随机取100个数。




6.Linux下的简单的命令,这些小命令都是常用的,比如问了查看网络端口号,用netstat,查看当前的所有进程用ps aux,还有添加用户使用useradd等等都是比较简单的。




7.已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10
解:
   int rand7()
{
    srand((int)time(NULL)); //参考
    return rand()%7 + 1;
}
int rand10()
{
    int x;
    do 
    {
        x = (rand7()-1) * 7 + rand7();
    }while(x > 40);
    return x % 10 + 1;
}




8.有1,2,…,n的无序数组,求排序算法,并且要求时间复杂度为O(n),空间复杂度O(1),使用交换,而且一次只能交换两个数。
解:
#include <stdio.h>


int main() {
    int a[] = {10, 6, 9, 5, 2, 8, 4, 7, 1, 3};
    int i, tmp;
    int len = sizeof(a) / sizeof(a[0]);
    for(i = 0; i < len;) {
        tmp = a[a[i] - 1];
        a[a[i] - 1] = a[i];
        a[i] = tmp;
        if(a[i] == i + 1) i++;
    }
    for(i = 0; i < len; ++i)
        printf("%d ", a[i]);
    printf("\n");
    return 0;
}




9.short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
解:
对于 short s1 = 1; s1 = s1 + 1;由于 s1+1运算时会自动提升表达式的类型,所以结果是 int
型,再赋值给 short 类型 s1时,编译器将报告需要强制转换类型的错误。
对于 short s1 = 1; s1 += 1;由于 +=是 java 语言规定的运算符,java 编译器会对它进行特殊
处理,因此可以正确编译。




10.最近公共祖先




11.必备知识点:
      排序:知道各种排序的时间和复杂度,能写出快排,堆排以及计数排序的代码且知道什么时候用哪种即可。 
      链表:知道构建动态链表,删除节点,翻转链表,两两翻转,求环节点,求两链表交点等。 
      字符串:知道高效翻转,回文,如果还能完整的写出KMP查找就基本完美。有时间再了解了解字典树,后缀树什么的更好。 
      树:知道二叉树的三种递归遍历,非递归遍历,查找,知道两种遍历求第三种,再深一点,知道如何分层遍历,如何求两节点距离。 
     其它:队列、栈、哈希表的特性和应用场合。




12.翻转二叉树
解:
/**
 
* Definition for a binary tree node.
 
* public class TreeNode {
 
*     int val;
 
*     TreeNode left;


*     TreeNode right;
 
*     TreeNode (int x) { val = x; }
 
* }
 
*/


public class Solution {
    
  public TreeNode invertTree (TreeNode root) {
    
    if (root == null) {
      
      return null;
    
    }
    
    root.left = invertTree (root.left);
     
    root.right = invertTree (root.right);


    
    TreeNode tmp = root.left;
     
    root.left = root.right;
     
    root.right = tmp;
    
    return root;
 
   }


}

猜你喜欢

转载自blog.csdn.net/u012571415/article/details/48829923