1、数组a[N],1-N-1这N-1个数存放在a[n]中,其中某个数重复一次,找出重复数字,时间复杂度必须是O(n)
int do_dup(int a[],int n)
{
int i,count=0,tmp=a[0];
int result = -1;
for (i=1;i<n;i++)
{
if(a[i]>tmp)
tmp=a[i];
}
int *b=malloc(tmp*sizeof(int));
for(i=0;i<n;i++)
{
if(b[a[i]]==0)
{
if(a[i]==0)
{
count+=1;
}
else
b[a[i]]=a[i];
if(count>=2)
{
result =0;
break;
}
}
else
{
result =b[a[i]];
break;
}
}
free(b);
return result;
}
2、一只青蛙一次可以跳一级台阶,也可以跳两级台阶,问n级台阶有多少种跳法?(这是一个斐波那契数列问题)
设f(n)为n级台阶的跳法,那么假设第一次跳出一步则剩下n-1级台阶,可用f(n-1)表示,第一次跳出两步则剩下n-2级台阶,可用f(n-2)表示,至此f(n) = f(n-1)+f(n-2),n>2。这是一道斐波那契数列题
int F(int n)
{
if(n == 1)
return 1;
int i,s3;
int s1 = 1;
int s2 = 1;
for(i=2;i<=n;i++)
{
s3 = s1+s2;
s1 = s2;
s2 = s3;
}
return s3;
}
int F_(int n)
{
if(n<=2)
reurn n;
return F_(n-1)+F_(n-2);
}
3、给定单向链表的头指针和一个节点指针,,定义一个函数在O(1)时间内删除该节点。(三种情况,不是尾节点,只有一个节点,是尾节点)
struct ListNode{
int m_nValue;
ListNode *m_pNext;
};
void DeleteNode(struct ListNode **ListHead,struct ListNode *isDelete)
{
if(*ListNode == NULL || isDelete == NULL)
return;
struct ListNode *pNode = *ListHead;
if(isDelete->m_pNext != NULL)
{
struct ListNode *pNext = isDelete->m_pNext;
isDelete->m_nValue = pNext->m_nValue;
isDelete->m_pNext = pNext->m_pNext;
delete pNext;
pNext = NULL;
}
else if(*ListHead == isDelete)
{
delete isDelete;
isDelete = NULL;
*ListHead = NULL;
}
else
{
struct ListNode *pNode = *ListNode;
while(pNode->m_pNext!=isDelete)
{
pNode=pNode->m_pNext;
}
pNode->m_pNext = NULL;
delete isDelete;
isDelete =NULL;
}
}
4、在一个已经排好序的链表中,如何删除重复的节点?
void DeleteDuplication(struct ListNode **ListHead)
{
if(*ListHead == NULL)
return;
struct ListNode *preNode = NULL;
struct ListNode *pNode = *ListHead;
while(pNode != NULL)
{
struct ListNde *pNext = pNode->m_pNext;
bool bFindNode = false;
if(pNext!=NULL && pNode->m_nValue == pNext->m_nValue)
bFindNode = true;
if(!bFindNode)
{
preNode = pNode;
pNode = pNode->m_pNext;
}
else
{
int value = pNode->m_nValue;
struct ListNode *pTobeDelete = pNode;
while(pTobeDelete->m_nValue == value)
{
pNext = pTobeDelete->p_mNext;
delete pTobeDelete;
pTobeDelete = NULL;
pTobeDelete = pNext;
}
if(preNode == NULL)
*ListHead = pNext;
else
preNode->p_mNext = pNext;
pNode = pNext;
}
}
}
5、正则表达式*和.的匹配实现,*表示前一个字符可以出现0或任意次,.表示前面字符可以是任意字符.
bool Match(char *str,char *rule)
{
if(str == NULL || rule == NULL)
return false;
return MatchCore(str,rule);
}
bool MatchCore(char *str,char *rule)
{
if(*str == '\0'&&rule == '\0')
return true;
if(*str!='\0' && rule == '\0')
return false;
if(*(rule+1) == '*')
{
if(*str==*rule ||(*str!='\0'&&*str=='.'))
{
return MatchCore(str,rule+2)|| //*号前面字符出现0次
MatchCore(str+1,rule+2)|| //*号前面字符只出现一次
MatchCore(str+1,rule); //*号前面字符出现大于一次
}
else
return MatchCore(str,rule+2);
}
if(*str==*rule || (*str!='\0'&&*str=='.'))
return MatchCore(str+1,rule+1);
return false;
}
6、判断一个输入字符串是不是表示数值,如果是返回true,否则返回false。例如:+123.123e+6,-.123E-3,123.e4
bool scanUnsignedInterger(char **str)
{
if(*str ==NULL)
return NULL;
char *before = *str;
if(**str!='\0' && **str>='0' && **str<='9')
{
++(*str);
}
return *str>before;
}
bool scanInterger(char **str)
{
if(*str == NULL)
return false;
if(*str=='+' || *str=='-')
++(*str);
return scanUnsignedInterger(str);
}
bool isNumber(char *str)
{
bool bNum = scanInterger(&str);
if(*str=='.')
{
++str;
bNum = scanUnsignedInterger(&str)||bNum;
}
if(*str == 'e' || *str == 'E')
{
++str;
bNum = scanInterger(&str)||bNum;
}
return bNum&&*str=='\0';
}
7、输入一个整型数组,实现一个函数来是的数组内的奇数排列在数组的前面,偶数排列在数组的后面。
void reorder(int *pData,int lenght,bool (*func)(int))
{
if(pData == NULL || length <= 0)
return;
int *start = pData;
int tmp;
int *end = pData+length-1;
while(start < end)
{
while(start<end && !func(*start))
start++;
while(start<end && func(*end))
end--;
if(start<end)
{
tmp = *start;
*start = *end;
*end = tmp;
}
}
}
bool isEvent(int n)
{
return (n&1)==0;
}
void ReorderOddEven(int *pData,int lenght)
{
if(pData == NULL || length <= 0)
return;
reorder(pData,length);
}
8、给出一个单向的链表,实现一个函数来找链表的倒数第k个节点。
struct ListNode_{
int m_nValue;
ListNode_ *m_pNext;
};
typedef struct ListNode_ ListNode;
ListNode *SearchKNode(ListNode *Head,unsigned int k)
{
if(Head == NULL)
return NULL;
ListNode *preNode = Head;
ListNode *behind = NULL;
for(int i=0;i<k-1;i++)
{
if(preNode->m_pNext == NULL)
return NULL;
preNode = preNode->m_pNext;
}
behind = Head;
while(preNode->m_pNext!=NULL)
{
preNode = preNode->m_pNext;
behind = behind->m_pNext;
}
return behind;
}
9、判断一个单链表是否有环?如果有找出环的入口点。
//1.首先判断环是否存在:创建两个指针p1、p2,p1走一步,p2走两步,p2指向尾节点之前能相遇则存在环,否则不存在。
ListNode *MeetingNode(ListNode *Head)
{
if(Head == NULL)
return NULL;
ListNode *pSlow = Head->m_pNext;
if(pSlow == NULL)
return NULL;
ListNode *pFast = pSlow->m_pNext;
while(pFast !=NULL)
{
if(pFast == pSlow)
return pFast;
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
if(pFast != NULL)
pFast = pFast->m_pNext;
}
return NULL;
}
ListNode *SearchHoopNode(ListNode *Head)
{
ListNode *meetnode = MeetingNode(Head);
if(meetnode == NULL)
return NULL;
int hoopNodeCount = 1;
ListNode *node = meetnode;
//找到环的节点数
while(node->m_pNext != meetnode)
{
node = node->m_pNext;
hoopNodeCount++;
}
ListNode *pFast = Head;
ListNode *pSlow = Head;
//找到环的入口节点
for(int i = 0;i < hoopNodeCount;i++)
{
if(pFast == NULL)
return NULL;
pFast = pFast->m_pNext;
}
while(pFast != NULL)
{
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
if(pFast == pSlow)
return pFast;
}
return NULL;
}
10、两种方式实现单链表的反转。
//递归实现
ListNode *ReverseList(ListNode *Node)
{
if(Node == NULL || Node->m_pNext == NULL)
return NULL;
ListNode *p = ReverseList(Node->m_pNext);
Node->m_pNext->m_pNext = Node;
Node->m_pNext = NULL;
return p;
}
//非递归实现
ListNode *ReverseList_(ListNode *Node)
{
if(Node == NULL)
return NULL;
//记录当前节点,前一个节点和后一个节点
ListNode *preNode = NULL;
ListNode *node = Node;
ListNode *pNext = NULL;
while(node->m_pNext != NULL)
{
pNext = node->m_pNext;
if(pNext->m_pNext == NULL)
return pNext;
node->m_pNext = preNode;
preNode = node;
node = pNext;
}
return NULL;
}
11、合并两个链表,如链表一:1,3,5...;链表二:2,4,6;合并后就是1,2,3,4,5,6
ListNode *MergeList(ListNode *root1,ListNode *root2)
{
if(root1 == NULL)
return root2;
if(root2 == NULL)
return root1;
ListNode *pListHead;
if(root1->m_nValue < root2->m_nValue)
{
pListHead = root1;
pListHead->m_pNext = MergeList(root1->m_pNext,root2);
}
else
{
pListHead = root2;
pListHead->m_pNext = MergeList(root1,root2->m_pNext);
}
return pListNode;
}
12、判断二叉树A是否是二叉树B的子结构,也就是子集。
bool HasSubTree(TreeNode *root1,TreeNode root2)
{
bool result = false;
if(root1 != NULL &&root2 != NULL)
{
result = Tree1HasTree2(root1,root2);
if(!result)
result = HasSubTree(root1->m_pLeft,root2);
if(!result)
result = HasSubTree(root1->m_pRight,root2);
}
return result;
}
bool Tree1HasTree2(TreeNode *root1,TreeNode *root2)
{
if(root1 == NULL)
return false;
if(root2 == NULL)
return true;
if(!Equal(root1->m_pValue,root2->m_pValue))
return false;
return Tree1HasTree2(root1->m_pLeft,root2->m_pLeft)&&Tree1HasTree2(root1->m_pRight,root2->m_pRight);
}
bool Equal(double value1,double value2)
{
double res = value1 - value2;
if(res >-0.0000001 && res<0.0000001)
return true;
else
return false;
}
13、编写一个函数实现二叉树镜像。
void MirrorBinaryTree(BinaryTree *root)
{
if(root == NULL)
return;
if(root->m_pLeft == NULL && root->m_pRight == NULL)
return;
BinaryTree *pTemp = root->m_pLeft;
root->m_pLeft = root->m_pRight;
root->m_pRight = pTemp;
if(root->m_pLeft)
MirrorBinaryTree(root->m_pLeft);
if(root->m_pRight)
MirrorBinaryTree(root->m_pRight);
}
14、编写一个函数判断一颗二叉树是不是对称树。
bool isSymmetical(BinaryTree *root)
{
return Symmetrical(root,root);
}
bool Symmetical(BinaryTree *root1,BinaryTree *root2)
{
if(root1 == NULL && root2 ==NULL)
return true;
if(root1 == NULL || root2 == NULL)
return false;
if(root1->m_nValue != root2->m_nValue)
return false;
return Symmetical(root1->m_pLeft,root2->m_pRight)&&
Symmetical(root1->m_pRight,root2->m_pLeft);
}
15、编写一个函数实现顺时针打印矩阵
/***************************
*** 1、从左到右打印
*** 2、从上到下打印
*** 3、从右到左打印
*** 4、从下到上打印
***************************/
int PrintCircle(const char **str,int colunms,int rows)
{
int start = 0;
if(str == NULL || colunms <= 0 || rows <= 0)
return -1;
while(colunms > start*2 && rows > start*2)
{
PrintACircle(str,colunms,rows,start);
start++;
}
return 0;
}
int PrintACircle(const char **str,int colunms,int rows,int start)
{
int i;
int endX = colunms-start-1;
int endY = rows-start-1;
for(i=0;i<=endX;i++)
{
printf("%d ",colunms[start][i]);
}
if(start < endY)
{
for(i=start+1;i<=endY;i++)
{
printf("%d ",colunms[endX][i]);
}
}
if(start<endX && start<endY)
{
for(i=endX-1;i>=start;i--)
{
printf("%d ",colunms[i][endY]);
}
}
if(start<endX && start<endY-1)
{
for(i=endY-1;i>=start+1;i--)
{
printf("%d ",colunms[start][i]);
}
}
return 0;
}
16、有两个序列,其中一个是入栈序列,实现一个函数判断另外一个序列是不是它的出栈序列。
bool isPopNums(const char *pPush,const char *pPop,int nLength)
{
bool bFlag = false;
if(pPush == NULL || pPop == NULL || nLength <= 0)
retun false;
char *pNextPop = pPop;
char *pNextPush = pPush;
while(pNextPop - pPop < nLength)
{
stack<int> p;
while(p.empty() || p.top() != *pNextPop)
{
if(pNextPush - pPush == nLength)
brak;
p.push(*pNextPush);
pNextPush++;
}
//如果没有一个数字匹配,则退出
if(p.top() != pNextPop)
break;
p.pop();
pNextPop++;
}
if(p.empty() && pNextPop - pPop == nLength)
bFlag = true;
return bFlag;
}
17、实现一个函数从上到下打印二叉树
/******************************************
*** 二叉树的前序、中序和后序遍历可以
*** 使用递归简单实现
*** 从上到下打印队列需要借助队列的先进先出的特性
*******************************************/
int PrintBinaryTree(BinaryTreeNode *root)
{
if(root == NULL)
return -1;
dequeue<BinaryTreeNode *> q;
q.push_front(root);
while(node.size())
{
BinaryTreeNode *Nodes = q.front();
q.pop_front();
printf("%d",Nodes->m_nValue);
if(Nodes->m_pLeft)
{
q.push_front(Nodes->m_pLeft);
}
if(Nodes->m_pRight)
{
q.push_front(Nodes->m_pRight);
}
}
return 0;
}
18、在17题的基础上,使得二叉树分层打印,即每一层对应新的一行,从左到右,从上到下。
int PrintTree(BinaryTree *root)
{
if(root == NULL)
return -1;
int nPreLevel = 1;
int nNextLevel = 0;
std::queue<BinaryTree *> q;
q.push(root);
while(!q.empty())
{
BinaryTree *Node = q.top();
q.pop();
printf("%d\t",Node->m_nValue);
if(Node->m_pLeft)
{
q.push(Node->m_pLeft);
++nNextLevel;
}
if(Node->m_pRight)
{
q.push(Node->m_pRight);
++nNextLevel;
}
--nPreLevel;
if(nPreLevel == 0)
{
printf("\n");
nPreLevel = nNextLevel;
nNextLevel = 0;
}
}
return 0;
}
19、实现一个函数,按之字形打印二叉树。
/*******************************
*** 第一次打印根节点
*** 第二次从右到左打印
*** 第三次从左到右打印
*** 创建两个栈,当打印的行数是奇数时,
将其子节点按从左到右入栈1;
当打印的偶数时,将其子节点按
从右到左入栈
*******************************/
int Print(BinaryTree *root)
{
std::stack<BinaryTree *> stack_[2];
int current = 0;
stack_[current].push(root);
while(!stack_[0].empty() || !stack_[1].empty())
{
BinaryTree *Node = stack_[current].top();
stack_[current].pop();
printf("%d\t",Node->m_nValue);
if(current == 0)
{
if(Node->m_pLeft)
stack_[1].push(Node->m_pLeft);
if(Node->m_pRight)
stack_[1].push(Node->m_pRight);
}
else
{
if(Node->m_pRight)
stack_[0].push(Node->m_pRight);
if(Node->m_pLeft)
stack_[0].push(Node->m_pLeft);
}
if(stack_[current].empty())
{
current = 1 - current;
printf("\n");
}
}
return 0;
}
20、实现一个函数,判断输入的一个整数序列是否为搜索二叉树的后序遍历序列。
bool isTreePostOrder(const char *s,int length)
{
if(s == NULL || length <= 0)
return false;
int root_num = s[length-1];
for(int i=0;i<length-1;i++)
{
if(s[i] > root_num)
break;
}
for(int j =i;j<length-1;j++)
{
if(s[j] <= root_num)
return false;
}
bool Left = true;
bool Right = true;
if(i < length-1)
Left = isTreePostOrder(s,i);
if(j > i)
Right = isTreePostOrder(s+i,length-i-1);
return (Left&Right);
}
21、输入一个的整数,判断二叉树中存在多少条路径,使得路径节点和等于输入整数。
bool FindPath(BinaryNode *root,int number)
{
if(root == NULL)
return false;
std::vector<int> path;
int sum = 0;
FindPath(root,number,path,sum);
return true;
}
void FindPath(BinaryNode *root,int number,std::vector<int> &path,int sum)
{
path.push_back(root->m_nValue);
sum += root->m_nValue;
if(root->m_pLeft==NULL && root->m_pRight==NULL && sum == number)
{
for(vector<int>::iterator it=path.begin();it<path.end();it++)
{
cout<<*it<<endl;
}
sum -= root->m_nValue;
}
if(root->m_pLeft)
FindPath(root->m_pLeft,number,path,sum);
if(root->m_pRight)
FindPath(root->m_pRight,number,path,sum);
path.pop_back();
}
22、复杂链表的复制
/********************************************
*** 分为三步进行链表的复制
*** 1、将链表扩大一倍,复制每一个节点并插入该节点的后面
*** 2、完成对m_pOther指针的指向
*** 3、分拆链表,节点是偶数的是新链表,节点为奇数则为原始链表
*********************************************/
struct LIST{
int m_nValue;
struct LIST *m_pNext;
struct LIST *m_pOther;//该指针指向链表的任意节点,也可以是NULL
};
bool connectList(struct LIST *pHead)
{
if(pHead == NULL)
return false;
struct LIST *pNode = pHead;
while(pNode != NULL)
{
struct LIST *pcloneNode =new LIST();
pcloneNode->m_nValue = pNode->m_nValue;
pcloneNode->m_pNext = pNode->m_pNext;
pcloneNode->m_pOther = NULL;
pNode->m_pNext=pcloneNode;
pNode = pcloneNode->m_pNext;
}
return true;
}
bool connectOtherNode(struct LIST *pHead)
{
if(pHead == NULL)
return false;
struct LIST *pNode = pHead;
while(pNode != NULL)
{
struct LIST *pCloned = pNode->m_pNext;
if(pNode->m_pOther != NULL)
{
pCloned->m_pOther = pNode->m_pOther->m_pNext;
}
pNode = pCloned->m_pNext;
}
return true;
}
struct LIST *reconnetList(struct LIST *pHead)
{
if(pHead == NULL)
return NULL;
struct LIST *pcloneNode = NULL;
struct LIST *pNode = pHead;
struct LIST *pcloneHead = NULL;
if(pNode->m_pNext != NULL)
{
pcloneHead = pcloneNode = pNode->m_pNext;
pNode->m_pNext = pcloneNode->m_pNext;
pNode = pNode->m_pNext;
}
while(pNode != NULL)
{
pcloneNode->m_pNext = pNode->m_pNext;
pcloneNode = pcloneNode->m_pNext;
pNode->m_pNext = pcloneNode->m_pNext;
pNode = pNode->m_pNext;
}
return pcloneHead;
}
struct LIST *Clone(struct LIST *pHead)
{
connectList(pHead);
connectOtherNode(pHead);
return reconnectList(pHead);
}
23、已知一颗二叉树,实现一个函数将二叉树变成排好序的双向链表。
BinaryNode *CreatList(BinaryNode *root)
{
if(root == NULL)
return NULL;
BinaryNode *pOfList;
CreatListNode(root,&pOfList);
//返回头结点
BinaryNode *pOfListHead = pOfList;
while(pOfListHead != NULL && pOfListHead->m_pLeft != NULL)
{
pOfListHead = pOfListHead->m_pLeft;
}
return pOfListHead;
}
void CreatListNode(BinaryNode *root,BinaryNode **pOfList)
{
if(root == NULL)
return;
BinaryNode *pOfListNode = *root;
if(root->m_pLeft != NULL)
CreatListNode(root->m_pLeft,pOfList);
pOfListNode->m_pLeft = *pOfList;
if(*pOfList != NULL)
(*pOfList)->m_pRight = pOfListNode;
*pOfList = root;
if(root->m_pRight != NULL)
CreatListNode(root->m_pRight,pOfList);
}
24、求一个整型数组中连续元素和的最大值,即[1,-3,4,5,7,-1,9,-4]数组的最大和就是4+5+7-1+9 = 24
bool isRightInput = true;
int GreateSum(int *s,int length)
{
int i;
int curSum = 0;
int greatSum = 0;
if(s == NULL || length <= 0)
{
isRightInput = false;
return 0;
}
for(i=0;i<length;i++)
{
if(curSum <= 0)
curSum = s[i];
else
curSum += s[i];
if(curSum > greatSum)
greatSum = curSum
}
return greatSum;
}
25、一个数字串“01234567891011.....”排列,第零位是0,第五位是5,实现一个函数输入一个整数N,求第N位的数字是多少?
int numbersOfDigits(int digits)
{
if(digits <= 0)
return 0;
//0-9有九位(0是第0位)10-99有2*90=180位
return 9*pow(10,digits-1);
}
int GetNbitNum(int index,int digits)
{
if(index < 0 || digits < 1)
return -1;
int i;
//求出第n位在哪个整数中,比如在370
int number = pow(10,digits-1) + index/digits;
//求出在该整数的第几位,比如第一位是7
int num = digits - index%digits;
for(i=1;i<num;i++)
number /= 10;
return number%10;
}
int GetNum(int index)
{
if(index <= 9 )
return index;
int digits = 1;
while(index)
{
int number = numbersOfDigits(digits);
if(index < number*digits)
return GetNbitNum(index,digits);
//计算index位于哪一个区间,0-9,10-99,100-999......
index -= number*digits;
digits++;
}
return -1;
}
26、编写一个函数实现atoi的功能
enum {eValid=0,eInValid};
int g_Status = eInValid;
int StrToInt(const char *str)
{
bool flag = false;
long long num = 0;
if(str != NULL && *str != '\0'){
if(*str == '+'){
str++;
flag = true;
}
else if(*str == '-'){
str++;
}
if(*str != '\0')
num = StrToIntCore(str,flag);
}
return (int)num;
}
long long StrToIntCore(const char *str,bool flag)
{
long long num = 0;
int flag_ = flag?1:-1;
while(*str !='\0')
{
if(*str>='0' &&*str<='9')
{
num = 10*num + flag_*(*str-'0');
if((flag && num>0x7FFFFFFF)||(!flag && num < 0x80000000))
{
num =0 ;
break;
}
}
else
{
num = 0 ;
break;
}
str++:
}
if(*str == '\0')
g_Status = g_Valid;
return num;
}
题目出处:以笔上试题均出自书本剑指Offer第二版