1.二维数组中的查找

/*
题目:在一个二维数组中,没一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
*/
#include<stdio.h>
#include<string.h> // 从右上角开始比较 bool Find(int *matrix, int rows, int columns, int number) {
bool found = false;
if (matrix != NULL && rows > && columns > ) {
int row = ;
int column = columns - ;
while (row < rows&&column >= ) {
if (matrix[row*columns + column] == number) {
found = true;
break;
}
else if (matrix[row*columns + column ]> number)
column--;
else
row++;
}
}
return found;
} // 从左下角开始比较
bool Find_2(int *arr, int rows, int columns, int number) {
bool find = false;
if (arr != NULL&&rows > && columns > ) {
int row = rows - ;
int column = ;
while (row >= && column <= columns - ) {
if (arr[row*columns + column] == number) {
find = true;
break;
}
else if (arr[row*columns+column] < number)
column++;
else
row--;
}
}
return find;
} int main() {
int arr [][]= {
{, , , },
{, , ,},
{, , , },
{, , , }
};
Find_2(*arr, , , );
return ;
}

2.字符串

  C/C++中的每个字符串都以’\0’结尾。为了节省空间,C/C++经常把常量字符串放到一个单独的内存区域。当几个指针赋值给相同的常量字符串时,它们实际会指向相同的地址空间。例如:

#include<stdio.h>
int main() {
char str1[] = "Hello World";
char str2[] = "Hello world"; char *str3 = "Hello world";
char *str4 = "Hello world";
if (str1 == str2)
printf("str1 and str2 are same. \n");
else
printf("str1 and str2 are not same.\n");
if (str3 == str4)
printf("str3 and str4 are same.\n");
else
printf("str3 and str4 are not same.\n");
return ;
}

输出如下:

str1 and str2 are not same.
str3 and str4 are same.

  

  题目:请实现一个函数,把字符串中的每个空格替换成”%20”。例如输入“We are happy.”,则输出为”We%20are%20%20happy.”。实现代码如下:

#include<stdio.h>
// lenght 为字符数组string的总容量
void ReplaceSpace(char string[], int length) {
if (string == NULL&&length <= )
return;
// originalLenght为字符串string的实际长度
int originalLenght = ;
int numOfBlank = ;
int i = ;
while (string[i] != '\0') {
originalLenght++;
if (string[i] == ' ')
numOfBlank++;
i++;
}
int newLenght = originalLenght + numOfBlank * ;
if (newLenght <= originalLenght)
return; int indexOfOriginal = originalLenght;
int indexOfNew = newLenght;
while (indexOfOriginal >= && indexOfNew > indexOfOriginal) {
if (string[indexOfOriginal] == ' ') {
string[indexOfNew--] = '';
string[indexOfNew--] = '';
string[indexOfNew--] = '%';
}
else
string[indexOfNew--] = string[indexOfOriginal];
indexOfOriginal--;
}
} int main() {
char string[] = "We are happy.";
int lenght = sizeof(string) / sizeof(char);
ReplaceSpace(string, lenght);
int j = ;
while (string[j] != '\0') {
printf("%c", string[j]);
j++;
}
printf("\n");
return ;
}

输出结果:

We%20are%20happy.

  

  相关题目:有两个排序的数组A1和A2,内存在A1末尾有足够的空余空间容纳A2。请实现一个函数,把A2中的所有数字插入到A1中并且所有的数字是排序的。实现代码如下:

#include<stdio.h>
// len1为数组arr1的有效数字的长度
void unionArray(int arr1[], int len1, int arr2[], int len2) {
// arr1_all是啊让人整个数组的空间长度
int arr1_all = len1 + len2;
if (len2 ==)
return;
int index_1 = len1-;
int index_2 = arr1_all-;
int index_3 = len2-;
while (index_2 > index_1) {
if (arr1[index_1] > arr2[index_3]) {
arr1[index_2--] = arr1[index_1];
index_1--;
}
else
{
arr1[index_2--] = arr2[index_3];
index_3--;
} } } int main() {
int arr1[] = { ,,, };
int arr2[] = { ,,,, };
unionArray(arr1, , arr2, );
int len = sizeof(arr1) / sizeof(int);
int i = ;
while (i < len) {
printf("%d", arr1[i]);
++i;
}
printf("\n");
return ;
}

输出结果:


3.链表

//    单向链表的节点定义
struct ListNode
{
int m_nValue;
ListNode *m_pNext;
}; // 往链表的末尾添加一个节点
void AddToTail(ListNode** pHead, int value) {
ListNode* pNew = new ListNode(); // 定义一个新节点指针并为它分配内存
pNew->m_nValue = value;
pNew->m_pNext = NULL; // 如果链表为空,则新添加的节点为头节点,使头指针pHead指向该节点
if (pHead == NULL) {
pHead = &pNew;
}
else {
ListNode* pNode = *pHead;
while (pNode->m_pNext != NULL)
pNode = pNode->m_pNext;
pNode->m_pNext = pNew; }
}
// 删除节点函数
void RemoveNode(ListNode** pHead, int value) {
if (pHead == NULL || *pHead == NULL) {
return;
}
ListNode *pToBeDeleted = NULL;
if ((*pHead)->m_nValue == value) {
pToBeDeleted = *pHead;
*pHead = (*pHead)->m_pNext;
}
else {
ListNode* pNode = *pHead;
while (pNode->m_pNext != NULL&&pNode->m_pNext->m_nValue!=value)
pNode = pNode->m_pNext;
if (pNode->m_pNext != NULL&&pNode->m_pNext->m_nValue == value) {
pToBeDeleted = pNode->m_pNext;
pNode->m_pNext = pNode->m_pNext->m_pNext;
}
if (pToBeDeleted != NULL) {
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}
}

题目:输入一个链表的头节点,从尾到头打印出每个节点的值。

//    题目:输入一个链表的头节点,从尾到头打印出每个节点的值。
// 方法一:从头到尾遍历链表,把节点依次放进一个栈中,当遍历完整个链表后,再从栈顶开始输出节点的值
void PrintListReversingly_Interatively(ListNode *pHead) {
std::stack<ListNode*> nodes; ListNode *pNode = pHead;
while (pNode != NULL) {
nodes.push(pNode);
pNode = pNode->m_pNext;
}
while (!nodes.empty()) {
pNode = nodes.top();
printf("%d\n", pNode->m_nValue);
nodes.pop();
}
} // 方法二:利用递归。每次访问一个节点时,先输出它后面的节点
void PrintListReversingly_Recursively(ListNode* pHead) {
if (pHead != NULL) {
if (pHead->m_pNext != NULL) {
PrintListReversingly_Recursively(pHead->m_pNext);
}
printf("%d\n", pHead->m_nValue);
}
} void haha(ListNode** pHead) {
while ((*pHead)->m_pNext != NULL)
{
printf("%d\n", (*pHead)->m_nValue);
(*pHead) = (*pHead)->m_pNext;
} }

4.树

  题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果都不含重复的数字。

#include<stdio.h>
#include<iostream> // 二叉树结点定义
struct BinaryTreeNode
{
int m_nvalue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
}; // 函数声明
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder,
int* startInorder, int* endInorder); // 用递归的方法构建左右子树和根节点 BinaryTreeNode* Construct(int *preorder, int *inorder, int length) {
if (preorder == NULL || inorder == NULL || length <= )
{
return NULL;
}
return ConstructCore(preorder,preorder+length-,inorder,inorder+length-);
}
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder,
int* startInorder, int* endInorder)
{
// 前序遍历第一个数字即为根节点的值
int rootValue = startPreorder[];
BinaryTreeNode* root = new BinaryTreeNode();
root->m_nvalue = rootValue;
root->m_pLeft = NULL;
root->m_pRight = NULL;
if (startPreorder == endPreorder)
{
if (startInorder == endInorder&&*startPreorder == *startPreorder)
return root;
else
throw std::exception("Invalid input");
}
// 在中序遍历中找到根节点的值
int* rootInorder = startPreorder;
while (*rootInorder != rootValue && rootInorder <= endInorder)
{
++rootInorder;
}
if (*rootInorder != rootValue&&rootInorder == endInorder)
throw std::exception("Invalid input"); int leftLength = rootInorder - startInorder;
int* leftPreorderEnd = startInorder + leftLength;
if (leftLength > ) {
// 构建左子树
root->m_pLeft = ConstructCore(startPreorder + , endPreorder,
startInorder, leftPreorderEnd - );
}
if (leftLength < endInorder - startInorder)
{
// 构建右子树
root->m_pRight = ConstructCore(leftPreorderEnd+,endPreorder,
rootInorder+,endInorder);
}
}

5.栈和队列

  题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能。

//    队列的声明
template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void); // 在队列末尾添加一个结点
void appendTail(const T& node); // 删除队列的头结点
T deleteHead(); private:
stack<T> stack1;
stack<T> stack2;
}; template <typename T> CQueue<T>::CQueue(void)
{
} template <typename T> CQueue<T>::~CQueue(void)
{
}

  接下来定义两个函数:

//    往第一个栈中插入元素
template<typename T> void CQueue<T>::appendTail(const T& element)
{
stack1.push(element);
} // 删除最先插入的元素
template<typename T> T CQueue<T>::deleteHead()
{
// 如果第二个栈为空,把栈一的元素依次弹出插入栈二
if (stack2.size() <= )
{
while (stack1.size()>)
{
T& data = stack1.top();
stack1.pop();
stack2.push(data);
}
} if (stack2.size() == )
throw new exception("queue is empty"); // 依次弹出并返回栈二栈顶元素
T head = stack2.top();
stack2.pop(); return head;
}

6.查找和排序

  题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。

//    利用二分查找法

#include<stdio.h>
#include<exception>
int MinInOrder(int* numbers, int index1, int index2); int Min(int* numbers, int length)
{
if (numbers == NULL || length <= )
throw new std::exception("Invalid parameters"); int index1 = ;
int index2 = length - ;
int indexMid = index1;
while (numbers[index1] >= numbers[index2])
{
// 如果index1和index2指向相邻的两个数,
// 则index1指向第一个递增子数组的最后一个数字,
// index2指向第二个子数组的第一个数字,也就是数组中的最小数字
if (index2 - index1 == )
{
indexMid = index2;
break;
} // 如果下标为index1、index2和indexMid指向的三个数字相等,
// 则只能顺序查找
indexMid = (index1 + index2) / ;
if (numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])
return MinInOrder(numbers, index1, index2); // 缩小查找范围
if (numbers[indexMid] >= numbers[index1])
index1 = indexMid;
else if (numbers[indexMid] <= numbers[index2])
index2 = indexMid;
} return numbers[indexMid];
} int MinInOrder(int* numbers, int index1, int index2)
{
int result = numbers[index1];
for (int i = index1 + ; i <= index2; ++i)
{
if (result > numbers[i])
result = numbers[i];
} return result;
} // ====================测试代码====================
void Test(int* numbers, int length, int expected)
{
int result = ;
try
{
result = Min(numbers, length); for (int i = ; i < length; ++i)
printf("%d ", numbers[i]); if (result == expected)
printf("\tpassed\n");
else
printf("\tfailed\n");
}
catch (...)
{
if (numbers == NULL)
printf("Test passed.\n");
else
printf("Test failed.\n");
}
} int main()
{
// 典型输入,单调升序的数组的一个旋转
int array1[] = { , , , , };
Test(array1, sizeof(array1) / sizeof(int), ); // 有重复数字,并且重复的数字刚好的最小的数字
int array2[] = { , , , , , };
Test(array2, sizeof(array2) / sizeof(int), ); // 有重复数字,但重复的数字不是第一个数字和最后一个数字
int array3[] = { , , , , , };
Test(array3, sizeof(array3) / sizeof(int), ); // 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
int array4[] = { , , , , };
Test(array4, sizeof(array4) / sizeof(int), ); // 单调升序数组,旋转0个元素,也就是单调升序数组本身
int array5[] = { , , , , };
Test(array5, sizeof(array5) / sizeof(int), ); // 数组中只有一个数字
int array6[] = { };
Test(array6, sizeof(array6) / sizeof(int), ); // 输入NULL
Test(NULL, , ); return ;
}

7.递归和循环

  递归虽然有简洁的优点,但是缺点也是显著的。由于递归式函数调用自身,而函数的调用是由空间和时间消耗的,所以递归的效率不如循环。

  题目一:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列定义如下:

  F()=,F()=, F(n)=F(n-)+F(n-)(n>=)

  解答代码:

#include<stdio.h>
#include <cassert> // ====================方法1:递归====================
// 时间复杂度以n的指数方式递增 long long Fibonacci_Solution1(unsigned int n)
{
if (n <= )
return ; if (n == )
return ; return Fibonacci_Solution1(n - ) + Fibonacci_Solution1(n - );
} // ====================方法2:循环====================
// 时间复杂度为O(n) long long Fibonacci_Solution2(unsigned n)
{
int result[] = { , };
if (n < )
return result[n]; long long fibNMinusOne = ;
long long fibNMinusTwo = ;
long long fibN = ;
for (unsigned int i = ; i <= n; ++i)
{
fibN = fibNMinusOne + fibNMinusTwo; fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
} return fibN;
} // ====================方法3:基于矩阵乘法====================
// 时间复杂度为O(logn) struct Matrix2By2
{
Matrix2By2
(
long long m00 = ,
long long m01 = ,
long long m10 = ,
long long m11 =
)
:m_00(m00), m_01(m01), m_10(m10), m_11(m11)
{
} long long m_00;
long long m_01;
long long m_10;
long long m_11;
}; Matrix2By2 MatrixMultiply
(
const Matrix2By2& matrix1,
const Matrix2By2& matrix2
)
{
return Matrix2By2(
matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10,
matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11,
matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10,
matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11);
} Matrix2By2 MatrixPower(unsigned int n)
{
assert(n > ); Matrix2By2 matrix;
if (n == )
{
matrix = Matrix2By2(, , , );
}
else if (n % == )
{
matrix = MatrixPower(n / );
matrix = MatrixMultiply(matrix, matrix);
}
else if (n % == )
{
matrix = MatrixPower((n - ) / );
matrix = MatrixMultiply(matrix, matrix);
matrix = MatrixMultiply(matrix, Matrix2By2(, , , ));
} return matrix;
} long long Fibonacci_Solution3(unsigned int n)
{
int result[] = { , };
if (n < )
return result[n]; Matrix2By2 PowerNMinus2 = MatrixPower(n - );
return PowerNMinus2.m_00;
} // ====================测试代码====================
void Test(int n, int expected)
{
if (Fibonacci_Solution1(n) == expected)
printf("Test for %d in solution1 passed.\n", n);
else
printf("Test for %d in solution1 failed.\n", n); if (Fibonacci_Solution2(n) == expected)
printf("Test for %d in solution2 passed.\n", n);
else
printf("Test for %d in solution2 failed.\n", n); if (Fibonacci_Solution3(n) == expected)
printf("Test for %d in solution3 passed.\n", n);
else
printf("Test for %d in solution3 failed.\n", n);
} int main()
{
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, );
Test(, ); Test(, ); return ;
}

  题目二:一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级台阶有多少种跳法。

  其实这道题的解答就是求上面的斐波那契数列。

8.位计算

  位运算是把数字用二进制表示之后,对每一位上0或者1的运算。

  题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1.因此如果输入为9,输出为2.

/*考虑到有负数的情况,如果只是对输入进行简单的右移,那么负数的高位会自动的添加1则可能会进入死循环*/

/*常规解法:
不进行右移,先把输入与标志位进行与判断最低位是不是1,再把标志位进行左移判断次低位是不是1
依次类推直到最高位,即可计算出1的个数
*/ int NumberOf1(int n){
int count=;
unsigned int flag=;
while(flag){
if(n&flag)
count++;
flag<<;
}
return count; } /*进阶解法:
可进行论证把一个数减去1,再和原来数做与运算,会把该整数最右边一个1变成0。例如1100,减去1后为1011,两数与后为1000。
*/
int NumberOf2(int n){
int count=;
while(n){
++count;
n=(n-)&n;
}
return count;
}

《剑指offer》习题解答(C/C++)的更多相关文章

  1. 九度OJ 上剑指 offer 习题目录

    <剑指Offer>面试题集收录汇总 面试题1 赋值运算符函数 不适合在线模式 面试题2 实现Singleton模式 不适合在线模式 面试题3 二维数组中的查找 已收录 面试题4 替换空格 ...

  2. 剑指offer题目解答合集(C++版)

    数组中重复的数字 二维数组中查找 字符串 替换空格 二叉树的编码和解码 从尾到头打印链表 重建二叉树 二叉树的下一个节点 2个栈实现队列 斐波那契数列 旋转数字 矩阵中的路径 机器人的运动范围 剪绳子 ...

  3. 【剑指Offer面试编程题】题目1354:和为S的连续正数序列--九度OJ

    题目描述: 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久, ...

  4. 【剑指Offer面试编程题】题目1509:树中两个结点的最低公共祖先--九度OJ

    题目描述: 给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先. 输入: 输入可能包含多个测试样例. 对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数 ...

  5. 【剑指Offer面试编程题】题目1508:把字符串转换成整数--九度OJ

    题目描述: 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 输入: 输入可能包含多个测试样例. 对于每个测试案例,输入为一个合法或者非法的字符串,代表一个整数n(1<= n&l ...

  6. 【剑指Offer面试编程题】题目1507:不用加减乘除做加法--九度OJ

    题目描述: 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 输入: 输入可能包含多个测试样例. 对于每个测试案例,输入为两个整数m和n(1<=m,n<=10 ...

  7. 【剑指Offer面试编程题】题目1506:求1+2+3+...+n--九度OJ

    题目描述: 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 输入: 输入可能包含多个测试样例. 对于每个 ...

  8. 【剑指Offer面试编程题】题目1356:孩子们的游戏(圆圈中最后剩下的数)--九度OJ

    题目描述: 每年六一儿童节,JOBDU都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为JOBDU的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈. ...

  9. 【剑指Offer面试编程题】题目1355:扑克牌顺子--九度OJ

    题目描述: LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他 ...

  10. 【剑指Offer面试编程题】题目1360:乐透之猜数游戏--九度OJ

    题目描述: 六一儿童节到了,YZ买了很多丰厚的礼品,准备奖励给JOBDU里辛劳的员工.为了增添一点趣味性,他还准备了一些不同类型的骰子,打算以掷骰子猜数字的方式发放奖品.例如,有的骰子有6个点数(点数 ...

随机推荐

  1. 利用Python分析GP服务运行结果的输出路径 & 实现服务输出路径的本地化 分类: Python ArcGIS for desktop ArcGIS for server 2015-08-06 19:49 3人阅读 评论(0) 收藏

    最近,一直纠结一个问题:做好的GP模型或者脚本在本地运行,一切正常:发布为GP服务以后时而可以运行成功,而更多的是运行失败,甚至不能知晓运行成功后的结果输出在哪里. 铺天盖地的文档告诉我,如下信息: ...

  2. javascript 知道这20个正则表达式,能让你少写1,000行代码

    正则表达式,一个十分古老而又强大的文本处理工具,仅仅用一段非常简短的表达式语句,便能够快速实现一个非常复杂的业务逻辑.熟练地掌握正则表达式的话,能够使你的开发效率得到极大的提升. 正则表达式经常被用于 ...

  3. nginx repos

    vim /etc/yum.repos.d/nginx.repo 然后将下面的内容复制进去: [nginx] name=nginx repo baseurl=http://nginx.org/packa ...

  4. 聪明的打字员---poj1184(bfs)

    题目链接:http://poj.org/problem?id=1184 分析:首先可以发现有6*10^6种状态,比较多,不过搜索的时候可以去除一些无用的状态, 可以发现一个点的值(2-5)如果想要改变 ...

  5. RabbitMQ(转)

    add by zhj: 如果用Python,那可以用celery,它是一个分布式任务队列,它的broker可以选择Rabbitmq/Redis/Mongodb等, celery通过Kombu这个lib ...

  6. springboot的相关信息

    Maven的配置:zzp_settings.xml <?xml version="1.0" encoding="UTF-8"?> <setti ...

  7. Visual Studio Code常用设置

    Visual Studio Code常用设置 • 自动保存设置 ▶ 文件(F) -> 首选项(P) -> 用户设置(U) ▶ 将"files.autoSave": &q ...

  8. MongoDB之Replica Set(复制集复制)

    MongoDB支持两种复制模式: 主从复制(Master/Slave) 复制集复制(Replica Set) 下面主要记录我在centos虚拟机上安装replica set,主要参考:http://d ...

  9. 字典树 trie

    Trie树        Trie树,就是字母树.Trie树是多叉树,每个节点为一个字母.其根节点为象征节点(就是说没有含义,但是存在这个节点),从根节点开始建立,每个节点至多为26个子节点(不要我说 ...

  10. Android开发--取消AsyncTask

    在Android应用开发过程中,为了防止UI线程堵塞,耗时的工作都应该另起一个后台线程来完成,其中AsyncTask就是其中的一种方式.最近在案子中需要“停止/取消”某个AsyncTask,在网上查了 ...