80道面试题及其解法(三)
来源:互联网 发布:网络连接正常上不了网 编辑:程序博客网 时间:2024/06/08 20:14
现有LA与LB两个链表,已升序排列。将LA与LB合并后也按升序排列.
设指针pa与pb分别均指向LA与LB当前的结点,那么只需要每次比较当前的这两个节点,谁小就把谁加入到LC(新链表)中,然后小的这个链表的指针继续后移。这样最坏的复杂度也只是O(LENA+LENB),算法2的实现如下:
- //结点结构体定义
- struct LNode{
- int data;
- LNode *next;
- };
- typedef LNode * LinkList;
- void main()
- {//函数声明
- void creat_list(LinkList &L,int n);
- void merge_list(LinkList &La,LinkList &Lb,LinkList &Lc);
- void print_list(LinkList L);
- //主函数开始
- int n1,n2;
- LinkList La,Lb,Lc;
- printf("建立La链表开始:请先输入要建立的结点个数\n");
- scanf("%d",&n1);
- creat_list(La,n1);
- printf("La链表信息如下:\n");
- print_list(La);
- printf("建立Lb链表开始:请先输入要建立的结点个数\n");
- scanf("%d",&n2);
- creat_list(Lb,n2);
- printf("Lb链表信息如下:\n");
- print_list(Lb);
- printf("合并完两链表后如下:\n");
- merge_list(La,Lb,Lc);
- print_list(Lc);
- }
- void creat_list(LinkList &L,int n)
- { int i;
- LinkList p,q;
- L=(LinkList)malloc(sizeof(LNode));
- L->next=NULL;//建立头结点
- q=L;
- for (i=1;i<=n;i++)
- {p=(LinkList)malloc(sizeof(LNode));
- printf("请输入第%d个节点的数据:",i);
- scanf("%d",&p->data);
- q->next=p;
- q=q->next;//q后移
- }
- p->next=NULL;//最后一个节点是尾结点
- }
- void merge_list(LinkList &La,LinkList &Lb,LinkList &Lc)
- {LinkList pa,pb,pc;
- pa=La->next;pb=Lb->next;//a,b链表均指向自己的第一个结点
- pc=Lc=La;//Lc链表自始至终就没有建立过,实际上LC就是借助指针去连接la和lb中的结点
- while(pa&&pb)//不指向末尾
- {
- if (pa->data<=pb->data)//插入La
- {pc->next=pa;
- pc=pa;//pc后移
- pa=pa->next;//La后移
- }
- else
- {
- pc->next=pb;
- pc=pb;
- pb=pb->next;
- }
- }//结束该循环后应该会剩下一个链表没合并完(假设俩个链表长度不一样)
- pc->next=pa?pa:pb;//剩余
- }
- void print_list(LinkList L)
- {
- LinkList p=L->next;//指向第一个结点
- while(p)
- {
- printf("%3d",p->data);
- p=p->next;
- }
- printf("\n");
- }
题目描述:
一个循环有序数组(如:3,4,5,6,7,8,9,0,1,2),不知道其最小值的位置,要查找任一数值的位置。要求算法时间复杂度为log2(n)。
问题分析:我们可以把循环有序数组分为左右两部分(以mid = (low+high)/ 2为界),由循环有序数组的特点知,左右两部分必有一部分是有序的,我们可以找出有序的这部分,然后看所查找元素是否在有序部分,若在,则直接对有序部分二分查找,若不在,对无序部分递归调用查找函数。 代码如下:
#include <iostream> using namespace std; int binarySearch(int a[],int low,int high,int value) //二分查找
{
if(low>high)
return -1; int mid=(low+high)/2; if(value==a[mid])
return mid;
else if(value>a[mid])
return binarySearch(a,mid+1,high,value);
else
return binarySearch(a,low,mid-1,value);
} int Search(int a[],int low,int high,int value) //循环有序查找函数
{
int mid=(low+high)/2; if(a[mid]>a[low]) //左有序
{
if(a[low]<=value && value<=a[mid] ) //说明value在左边,直接二分查找
{
return binarySearch(a,low,mid,value);
} else //value在右边
{
return Search(a,mid+1,high,value);
}
}
else //右有序
{
if(a[mid]<=value && value<=a[high])
{
return binarySearch(a,mid,high,value);
}
else
{
return Search(a,low,mid-1,value);
}
}
} int main()
{
int a[]={3,4,5,6,7,8,9,0,1,2}; cout<<Search(a,0,9,0)<<endl; return 0;
}
二叉树学习之非递归遍历
二叉树递归遍历可谓是学过数据结构的同仁都能想一下就能写出来,但在应聘过程我们常常遇到的是写出一个二叉树非递归遍历函数,接着上篇文章写二叉树的非递归遍历,先难后易,一步一步的来.
先上代码:
- #include "binarytree.h"
- #include <stack>
- #include <queue>
- #ifndef RECU
- #warning("RECU is not defined")
- /**
- *前序遍历(根左右)
- *
- *1、当前节点为非空,访问当前节点,压栈其右子节点,考虑其左子节点
- *2、当前节点为NULL,出栈
- *
- *@param t to visit
- *@param visit point to a func
- */
- void pre_order(link t, void (*visit)(link))
- {
- std::stack<link> myStack;
- while( t || !myStack.empty() ) {
- if ( t ) {
- visit(t);
- myStack.push(t->rchild);
- t = t->lchild;
- } else {
- t = myStack.top();
- myStack.pop();
- }
- }
- }
- /**
- *中序序遍历(左根右)
- *
- *1、当前节点为非空,在访问当前节点前要先访问其左子节点,
- * 压栈当前节点,判断其左子结点,一直压栈左子节点
- *2、当前节点为NULL,出栈访问,其左子结点比当前节点出栈访问早,
- * 此时当前节点是其右节点的父节点的角色,考虑其右节点
- *
- *在遍历过程中角色转换很重要
- *
- *@param t to visit
- *@param visit point to a func
- */
- void in_order(link t, void (*visit)(link))
- {
- std::stack<link> myStack;
- while( t || !myStack.empty() ) {
- if ( t ) {
- myStack.push(t);
- t = t->lchild;
- } else {
- t = myStack.top();
- myStack.pop();
- visit(t);
- t = t->rchild;
- }
- }
- }
- /**
- *后序遍历(左右根)
- *
- *1、由于在访问当前树的根结点时,应先访问其左、右子树,因而先将根结点入栈,
- * 接着将右子树也入栈,然后考虑左子树,重复这一过程直到某一左子树为空
- *2、如果当前考虑的子树为空,
- * 1.若栈顶不为空,说明第二栈顶对应的树的右子树未处理,
- * 则弹出栈顶,下次循环处理,并将一空指针入栈以表示其另一子树已做处理;
- * 2.若栈顶也为空树,说明第二栈顶对应的树的左右子树或者为空,或者均已做处理,
- * 直接访问第二栈顶的结点,访问完结点后,若栈仍为非空,说明整棵树尚未遍历完,
- * 则弹出栈顶,并入栈一空指针表示第二栈顶的子树之一已被处理。
- *
- *@param t to visit
- *@param visit point to a func
- */
- void post_order(link t, void (*visit)(link))
- {
- std::stack<link> myStack;
- while( 1 ) {
- if ( t ) {
- myStack.push(t);
- myStack.push(t->rchild);
- t = t->lchild;
- } else {
- t = myStack.top();
- myStack.pop();
- if (!t) {
- t = myStack.top();
- myStack.pop();
- visit(t);
- if (myStack.empty())
- break;
- t = myStack.top();
- myStack.pop();
- }
- myStack.push(NULL);
- }
- }
- }
- #endif
- /**
- *层遍历
- *
- *@param t to visit
- *@param visit point to a func
- */
- void level_order(link t, void (*visit)(link))
- {
- std::queue<link> myQueue;
- if (t) {
- myQueue.push(t);
- while( !myQueue.empty() ) {
- link tmp = myQueue.front();
- myQueue.pop();
- visit(tmp);
- if (tmp->lchild != NULL)
- myQueue.push(tmp->lchild);
- if (tmp->rchild != NULL)
- myQueue.push(tmp->rchild);
- }
- }
- }
面试题整理-矩阵查找元素
需要在矩阵中查找元素。这个矩阵的排列如下:
每一行都是有序的。每一列都是有序的。
比如一个小矩阵。
10 30
20 80
现在,我们需要在一个这样N * M的矩阵中找到一个元素,并返回其位置。
思路
首先,这个题不太适合二分查找。因为并不能保证第二行的元素都一定比第一行的任意元素大。
所以应该是很难找到O(lgN)的算法。
每次都是取右上角的元素v与x(我们要查找的元素)进行比较较:
如果发现v > x,由于v所在列肯定比x大。所以v所在列可以舍弃。
如果发现v < x,由于v所在行肯定比x小。所以v所在行可能舍弃。
最后余下的,可能是一行,也可能是一列。总之可以利用二分查找来实现了。效率O(min(N, M)) + log(abs(M-N)).
解题
这里直接粘出代码。
- int find(int **a, const int row, const int col, const int x, int *rpos, int *cpos) {
- //右上角为起始点.
- int from_row = 0, from_col = col - 1, v;
- int b, e, mid;
- *rpos = *cpos = -1;
- while (from_row < row && from_col >= 0) {
- v = a[from_row][from_col];
- if (v == x) {
- *rpos = from_row;
- *cpos = from_col;
- return 1;
- }
- from_row += x > v;
- from_col -= v > x;
- }
- //最后剩下一行
- if (from_row == (row - 1) && from_col != 0) {
- b = 0, e = from_col + 1;
- while (b < e) {
- mid = b + ((e-b)>>1);
- v = a[from_row][mid];
- if (x == v) {
- *rpos = from_row;
- *cpos = mid;
- return 1;
- } else if (v > x) e = mid;
- else b = mid + 1;
- }
- return 0;
- }
- //最后剩下一列
- if (from_col == 0 && from_row != (row - 1)) {
- b = from_row, e = row;
- while (b < e) {
- mid = b + ((e-b)>>1);
- v = a[mid][0];
- if (v == x) {
- *rpos = mid;
- *cpos = from_col;
- return 1;
- } else if (v > x) e = mid;
- else b = mid + 1;
- }
- return 0;
- }
- //最后只剩下一个点
- if (a[from_row][from_col] == x) {
- *rpos = from_row;
- *cpos = from_col;
- return 1;
- }
- return 0;
- }
这里写一个测试程序,如果有错,会输出Error。
char
*
strstr
(
const
char
*s1,
const
char
*s2)
{
int
len2;
if
(!(len2=
strlen
(s2)))
//此种情况下s2不能指向空,否则strlen无法测出长度,这条语句错误
return
(
char
*)s1;
for
(;*s1;++s1)
{
if
(*s1==*s2 &&
strncmp
(s1,s2,len2)==0)
return
(
char
*)s1;
}
return
NULL;
}
char
*
strstr
(constchar*s1,constchar*s2)
{
int
n;
if
(*s2)
{
while
(*s1)
{
for
(n=0;*(s1+n)==*(s2+n);n++)
{
if
(!*(s2+n+1))
return
(
char
*)s1;
}
s1++;
}
return
NULL;
}
else
return
(
char
*)s1;
}
- 80道面试题及其解法(三)
- 80道常见数据结构面试题及其解法(2)
- 80道常见数据结构面试题及其解法
- Android面试题及其答案(三)
- 一道面试题及其扩展,求好解法
- Java知识点及其面试题整理三
- 面试题(三)
- 面试题(三)
- 三道PHP面试题
- 三道 华为 面试题
- 面试题(三)Java
- 常见面试题(三)
- 微软面试题(三)
- 面试题整理(三)
- Android面试题(三)
- iOS面试题(三)
- iOS面试题(三)
- 操作系统面试题(三)
- pku 3069 - Saruman's Army
- java表达式问题 十六进制的趣事
- 查看JSP和Servlet版本
- Linux简介
- Unique Paths II
- 80道面试题及其解法(三)
- 13. 通用的操作系统功能库(2)
- SHELL编程之常用技巧
- 设置代码的安全模式
- 迅雷9.0.10.300杂交版 超晶版 只有8M
- kafka集群搭建和使用Java写kafka生产者消费者
- SDN实战团分享
- ERROR:vtkOpenGLExtensionManager (0000025DBCBB4170): Extension GL_VERSION_1_2 could not be loaded.
- 功能代码的封装