《程序员面试攻略》题目总结

一. 链表

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;
 }
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值