继续
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
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;i2;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
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;iif(str[i]=='.' && str[i+1]!='.')
{
start = i+1;
}
if(str[i]!='.' && str[i+1]=='.')
{
end = i;
}
if(start//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
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
写起来简单,比快排避开了堆栈调用。