[心得]面试题分析与整理2

继续

5.单链表反转,字符串反转

typedef struct node *nodeLink;

struct node
{
    int data;
    nodeLink next;
};

void reverseSigleLink(nodeLink head)
{
    if(!head)   return;
    while(head->next)
    {
        nodeLink tmp = head;
        head->next = NULL;
        head->next->next = head;
        head = tmp;
    }
}

字符串反转比这个要简单一些,原因是字符串可以直接按位置进行索引。

#include <stdio.h>

void myswap(char *ch1, char *ch2)
{
    if (*ch1 == *ch2)   return;
    *ch1 = *ch1 + *ch2;
    *ch2 = *ch1 - *ch2;
    *ch1 = *ch1 - *ch2;
}

void reverseStr(char *str, int n)
{
    for(int i=0;i<n/2;i++)
    {
        myswap(&str[i], &str[n-1-i]);
    }
}


int main()
{
    char str[] = "Hello C.Hello C++..";
    printf("raw string is: %s\n", str);
    char expect[] = "..++C olleH.C olleH";
    printf("expect string is: %s\n\n", expect);

    reverseStr(str, sizeof(str)/sizeof(char)-1);

    printf("actual output is: %s\n", str);

    return 0;
}

这个题还引申出一个题,就是把字符串按某个字符进行反转。
比如,
Hello C.Hello C++..
期望的反转结果是:
..Hello C++.Hello C

实际的思路就是再多想一层,既然整体可以做反转,那么局部也可以做反转。
先局部反转分隔符之外的字符,然后再对整体做一次反转,应该可以得到结果。原来的反转函数稍作改造,支持按区间做反转。

#include <stdio.h>

void myswap(char *ch1, char *ch2)
{
    if (*ch1 == *ch2)   return;
    *ch1 = *ch1 + *ch2;
    *ch2 = *ch1 - *ch2;
    *ch1 = *ch1 - *ch2;
}

void reverseStr(char *str, int left, int right)
{
    for(int i=0;i<(right-left)/2;i++)
    {
        //printf("swap str[%d]:%c <-> str[%d]:%c\n",
        //  left+i, str[left+i], right-1-i, str[right-1-i]);
        myswap(&str[left+i], &str[right-1-i]);
    }
}


int main()
{
    char str[] = "Hello C.Hello C++..";
    int str_len = sizeof(str)/sizeof(char) -1;
    int start = 0;
    int end = 0;

    printf("raw string is: %s [%d]chars\n", str, str_len);
    //char expect[] = "..++C olleH.C olleH";
    char expect[] = "..Hello C++.Hello C";
    printf("expect string is: %s\n\n", expect);

    for(int i=0;i<str_len;i++)
    {
        if(str[i]=='.' && str[i+1]!='.')
        {
            start = i+1;
        }
        if(str[i]!='.' && str[i+1]=='.')
        {
            end = i;
        }
        if(start<end)
        {
            //printf("start=%d, end=%d\n",start, end);
            reverseStr(str, start, end+1);
            //printf("after partial reverse: %s\n", str);
            start = end;
        }
    }

    reverseStr(str, 0, str_len);

    printf("actual output is: %s\n", str);

    return 0;
}

第2段换序列时有点小坑,就是offset要仔细分析。

6.确定两个单链表有共同的部分
这个问题可以演化成判断树有共同祖先的问题,也是面试书上的原题。
基本思路,都往后走,若有共同部分,必然在链表的某个位置会合,如果到尾结点还没会合,那就是没有共同部分,因此这题本质上还是一个单链表的遍历问题。
编程之美233页

#include <iostream>
using namespace std;

typedef struct Node *NodeLink;
struct Node
{
    int data;
    NodeLink next;
};

NodeLink FindNode(NodeLink a, NodeLink b);
NodeLink getTail(NodeLink head);

int main()
{
    NodeLink a, b;
    a = b = 0;
    FindNode(a, b);
    return 0;
}

NodeLink FindNode(NodeLink a, NodeLink b)
{
    if(!a || !b)     return NULL;
    NodeLink tailA = getTail(a);
    NodeLink tailB = getTail(b);
    if(tailA==tailB)    return tailA;
    return NULL;
}

NodeLink getTail(NodeLink head)
{
    if(!head)   return NULL;
    while(head->next)
        head = head->next;
    return head;
}

7.判断一个ip是一个合法的ip
这个题目本质上是一个字符串遍历的问题。解出一段ip,然判断其值是不是合法,当4段ip值都合法,那就是一个合法的ip。

这个问题还有一个引申问法,就是判断两个ip是不是在同一个网段。这个问题本质是考察IP知识,编码倒不是重点。你得知道怎么判断ip,ip和掩码位与结果相同,那才是两个相同的网段。
具体代码略

8.shell排序
这个问题当时被面过,冒泡,选择,插入,快排,堆排,甚至连最复杂的归排都准备了,唯独希尔排序被问了。希尔排序是用步长控制的插入排序,通过加大插入排序的间隔,让数据大幅移动,时间复杂度NlogN。
还是来段代码说话:

void shell_sort(int *a, int n)
{
    int h,j,k,t;
    for(h=n/2;h>0;h=h/2)
    {
        t = a[j];
        for(k=j-h;(k>=0)&&t<a[k];k-=h)
        {
            a[k+h] = a[k];
        }
        a[k+h] = t;
    }
}

写起来简单,比快排避开了堆栈调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值