一. 链表
1. 链表中的倒数第m个元素
给定一个单向链表,请设计一个既节省时间又节省空间的算法来找出该链表中的倒数第m个元素。实现这个算法。
“倒数第m个元素”是这样规定的:当m=0时,链表的最后一个元素(尾元素)将被返回。
前进m步后启动一个“后指针”
2. 空链表和循环链表
给定一个链表,它可能是一个以"NULL"结尾的非循环链表,也可能是一个循环结构结尾的循环链表。写一个函数来判断该链表是一个循环链表还是一个非循环 链表,该函数不得对链表本身做任何修改。
用两个指针,一快一慢,如果是循环链表,快的指针迟早会 超过慢指针,时间复杂度:O(n),最多也是3n
int DetermineTermination(node *head)
{
node *fast, *slow;
fast = slow = head;
while(1){
if(!fast || !fast->next){
return 0;
}
else if(fast == slow || fast->next == slow){
return 1;
}
else {
slow = slow->next;
fast = fast->next->next;
}
}
}
二. 树和图
1. 树的遍历(递归+非递归)
注意递归转换非递归的分析过程。
2. 最低公共祖先
已知二分查找树上两个节点的值,请找出它们的最低公共祖先。你可以假设这两个值肯定存在。这个函数的调用接口如下所示:
int FindLowestCommonAncestor(node *root, int value1, int value2);
原理:两个节点的最低公共祖先的值介于两者之间。
做法:从根节点出发,沿着两个给定节点的公共祖先前进。当这个两个节点的值同时小于当前节点的值时,沿左指针前进;当这两个节点的值同时大于当前节点的值 时,沿右指针前进;当第一次遇到当前节点的值介于两个给定的节点值之间的情况时,这个当前节点就是我们的目标节点。
三. 字符串和数组
1. 第一个无重复字符
采用的方法是哈希表或者数组记录字符的出现次数,然后再从头遍历一次。
2. 颠倒单词的出现顺序
请编写一个函数来颠倒单词在字符串里的出现顺序。比如说,你的函数应该把字符串"Do or do not, there is no try."转化为"try. no is there not, do or Do"。假设所有的单词都以空格为分隔符,标点符号也当做字母来对待。
除了通用性解法外,可以采用一种专用的解法:交换字符, 头尾交换,然后再针对每一个单词头尾交换
void ReverseWords(char str[])
{
int start = 0, end = 0, length;
length = strlen(str);
//
ReverseString(str, start, length-1);
while(end < length){
if(str[end] != ' '){
//Save position of beginning of word
start = end;
//Scan to next non-word character
while(end < length && str[end] != ' '){
end++;
}
//Back up to end of word
end--;
//Reverse words
ReverseString(str, start, end);
}
end++; //Advance to next token
}
return;
}
ReverseString(char str[], int start, int end)
{
char temp;
while(end > start){
temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
}
四. 其他
1. 字节的升序存储和降序存储方式
请编写一个函数还判断某计算机的字节存储顺序是升序(little-endian)还是降序(big-endian)。
“字节的存储顺序”指的是多字节数据的各个字节在计算机里的存储顺序。比如说用来表示整数的那4个字节的顺序,其包括两种,一是按从最低位字节 (LSB)到最高位字节(MSB)的顺序进行存储;另一种是从MSB到LSB的顺序进行存储。这里说的“高位字节”指的是字(word)中的高位字节。如 果字节表示的是字的低值部分,我们就说它是这个字的LSB。比如说,数值“5A6C”中的LSB就是"6C"。反过来说,“5A6C”中的MSB是 “5A”。
在一台采用字节降序存储方案的计算机里,MSB将被保存在最低位的地址里;在一台采用字节升序存储方案的计算机里,LSB将被保存在最低位的地址里。比如 说,采用字节降序存储方案的计算机把十六进制值“A45C”中的"A4"保存在第一个字节里,把"5C"保存在第二个字节里;而一台采用字节升序存储方案 的计算机将把“5C”保存在第一个字节里,把"A4"保存在第二个字节里。
具体到本题中,可以使用字符指针来获取某个字节中的内容。
/* Return 1 if the machine is little-endian, 0 if the
* machine is big-endian
*/
int Endianness(void)
{
int testNum;
char *ptr;
testNum = 1;
ptr = (char *)&testNum;
return (*ptr);
}
有一种更精妙的解法,利用了“union”类型:这种类型与 “struct”类似,只是它的所有数据成员都是从内存中的同一个位置开始存储的。这样使你能够把同样的数据当做不同的变量类型来使用。
/* Return 1 if the machine is little-endian, 0 if the
* machine is big-endian
*/
int Endianness(void)
{
union{
int theInteger;
char singleByte;
} endianTest;
endianTest.theInteger = 1;
return endianTest.singleByte;
}