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;
}
}
解:
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;
}
}