# CodingInterview 一刷

### 1. 找出数组中重复的数字

1. 排序后遍历
2. 利用hash表，遍历数组，判断当前数字是否是在hash表中，没有，加入。有，则是重复数字。
3. n长的数组，数字范围0-n-1，则排好序的话，i位置上存放i值才是没有重复的。遍历数组，扫描到i位置，如果arr[i]==i,则扫描下一个位置，否则和第m=arr[i]的位置比较，如果相等，找到重复。如果不相等，交换两者。
``````bool duplicate(int numbers[], int length, int* duplication)
{
if(numbers == nullptr || length <= 0)
return false;

for(int i = 0; i < length; ++i)
{
if(numbers[i] < 0 || numbers[i] > length - 1)
return false;
}

for(int i = 0; i < length; ++i)
{
while(numbers[i] != i)
{
if(numbers[i] == numbers[numbers[i]])
{
*duplication = numbers[i];
return true;
}

// 交换numbers[i]和numbers[numbers[i]]
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}

return false;
}
``````

### 2. 不修改数组找出重复的数字

``````int getDuplication(const int* numbers, int length)
{
if(numbers == nullptr || length <= 0)
return -1;

int start = 1;
int end = length - 1;
while(end >= start)
{
int middle = ((end - start) >> 1) + start;
int count = countRange(numbers, length, start, middle);
if(end == start)
{
if(count > 1)
return start;
else
break;
}

if(count > (middle - start + 1))
end = middle;
else
start = middle + 1;
}
return -1;
}

int countRange(const int* numbers, int length, int start, int end)
{
if(numbers == nullptr)
return 0;

int count = 0;
for(int i = 0; i < length; i++)
if(numbers[i] >= start && numbers[i] <= end)
++count;
return count;
}
``````

### 3. 有序二维数组中找是否存在某个整数

``````bool Find(int* matrix, int rows, int columns, int number)
{
bool found = false;

if(matrix != nullptr && rows > 0 && columns > 0)
{
int row = 0;
int column = columns - 1;
while(row < rows && column >=0)
{
if(matrix[row * columns + column] == number)
{
found = true;
break;
}
else if(matrix[row * columns + column] > number)
-- column;
else
++ row;
}
}

return found;
}
``````

### 4 替换空格

``````void ReplaceBlank(char str[], int length)
{
if(str == nullptr && length <= 0)
return;

/*originalLength 为字符串str的实际长度*/
int originalLength = 0;
int numberOfBlank = 0;
int i = 0;
while(str[i] != '\0')
{
++ originalLength;

if(str[i] == ' ')
++ numberOfBlank;

++ i;
}

/*newLength 为把空格替换成'%20'之后的长度*/
int newLength = originalLength + numberOfBlank * 2;
if(newLength > length)
return;

int indexOfOriginal = originalLength;
int indexOfNew = newLength;
while(indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
{
if(str[indexOfOriginal] == ' ')
{
str[indexOfNew --] = '0';
str[indexOfNew --] = '2';
str[indexOfNew --] = '%';
}
else
{
str[indexOfNew --] = str[indexOfOriginal];
}

-- indexOfOriginal;
}
}

``````

### 5. 从尾到头打印链表

``````void PrintListReversingly_Iteratively(ListNode* pHead)
{
std::stack<ListNode*> nodes;

while(pNode != nullptr)
{
nodes.push(pNode);
pNode = pNode->m_pNext;
}

while(!nodes.empty())
{
pNode = nodes.top();
printf("%d\t", pNode->m_nValue);
nodes.pop();
}
}

{
{
{
}

}
}

``````

### 6.先序中序重建二叉树

``````BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);

BinaryTreeNode* Construct(int* preorder, int* inorder, int length)
{
if(preorder == nullptr || inorder == nullptr || length <= 0)
return nullptr;

return ConstructCore(preorder, preorder + length - 1,
inorder, inorder + length - 1);
}

BinaryTreeNode* ConstructCore
(
int* startPreorder, int* endPreorder,
int* startInorder, int* endInorder
)
{
// 前序遍历序列的第一个数字是根结点的值
int rootValue = startPreorder[0];
BinaryTreeNode* root = new BinaryTreeNode();
root->m_nValue = rootValue;
root->m_pLeft = root->m_pRight = nullptr;

if(startPreorder == endPreorder)
{
if(startInorder == endInorder && *startPreorder == *startInorder)
return root;
else
throw std::exception("Invalid input.");
}

// 在中序遍历中找到根结点的值
int* rootInorder = startInorder;
while(rootInorder <= endInorder && *rootInorder != rootValue)
++ rootInorder;

if(rootInorder == endInorder && *rootInorder != rootValue)
throw std::exception("Invalid input.");

int leftLength = rootInorder - startInorder;
int* leftPreorderEnd = startPreorder + leftLength;
if(leftLength > 0)
{
// 构建左子树
root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd,
startInorder, rootInorder - 1);
}
if(leftLength < endPreorder - startPreorder)
{
// 构建右子树
root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder,
rootInorder + 1, endInorder);
}

return root;
}
``````

### 7.二叉树的下一个结点

``````struct BinaryTreeNode
{
int                    m_nValue;
BinaryTreeNode*        m_pLeft;
BinaryTreeNode*        m_pRight;
BinaryTreeNode*        m_pParent;
};

BinaryTreeNode* GetNext(BinaryTreeNode* pNode)
{
if(pNode == nullptr)
return nullptr;

BinaryTreeNode* pNext = nullptr;
if(pNode->m_pRight != nullptr)
{
BinaryTreeNode* pRight = pNode->m_pRight;
while(pRight->m_pLeft != nullptr)
pRight = pRight->m_pLeft;

pNext = pRight;
}
else if(pNode->m_pParent != nullptr)
{
BinaryTreeNode* pCurrent = pNode;
BinaryTreeNode* pParent = pNode->m_pParent;
while(pParent != nullptr && pCurrent == pParent->m_pRight)
{
pCurrent = pParent;
pParent = pParent->m_pParent;
}

pNext = pParent;
}

return pNext;
}
``````

### 8.用栈实现队列。

``````template<typename T> void CQueue<T>::appendTail(const T& element)
{
stack1.push(element);
}

{
if(stack2.size()<= 0)
{
while(stack1.size()>0)
{
T& data = stack1.top();
stack1.pop();
stack2.push(data);
}
}

if(stack2.size() == 0)
throw new exception("queue is empty");

stack2.pop();

}
``````

### 9.斐波那契数列

``````long long Fibonacci_Solution1(unsigned int n)
{
if(n <= 0)
return 0;

if(n == 1)
return 1;

return Fibonacci_Solution1(n - 1) + Fibonacci_Solution1(n - 2);
}

long long Fibonacci_Solution2(unsigned n)
{
int result[2] = {0, 1};
if(n < 2)
return result[n];

long long  fibNMinusOne = 1;
long long  fibNMinusTwo = 0;
long long  fibN = 0;
for(unsigned int i = 2; i <= n; ++ i)
{
fibN = fibNMinusOne + fibNMinusTwo;

fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
}

return fibN;
}
``````

### 10.在旋转数组中查找某个数字

``````class Solution {
public:
int search(vector<int>& nums, int target) {
// 线性表搜索问题一般都会用到二分法
// 二分法涉及三个指针min max mid
int min = 0, max = nums.size()-1, mid = 0;
// 二分法最终的停止条件
while(min <= max){
// 初始第一次二分的mid
int mid = (min+max)/2;
// 如果mid恰好是target(最终target都会到mid这里)
if(nums[mid] == target)    return mid;
// 如果左半部分有序,则在此半部分（有序字符串）进行二分查找
if(nums[min] <= nums[mid]){
if(nums[min]<=target && target<nums[mid])
max = mid - 1;
else
min = mid + 1;
}
// 如果右半部分有序
else{
if(nums[mid]< target && target<=nums[max])
min = mid + 1;
else
max = mid - 1;
}
}
// 不满足最高二分条件min<=max时
return -1;
}
};
``````

### 11.矩阵中的路径

``````#include <cstdio>
#include <string>
#include <stack>

using namespace std;

bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, const char* str, int& pathLength, bool* visited);

bool hasPath(const char* matrix, int rows, int cols, const char* str)
{
if(matrix == nullptr || rows < 1 || cols < 1 || str == nullptr)
return false;

bool *visited = new bool[rows * cols];
memset(visited, 0, rows * cols);

int pathLength = 0;
for(int row = 0; row < rows; ++row)
{
for(int col = 0; col < cols; ++col)
{
if(hasPathCore(matrix, rows, cols, row, col, str,
pathLength, visited))
{
return true;
}
}
}

delete[] visited;

return false;
}

bool hasPathCore(const char* matrix, int rows, int cols, int row,
int col, const char* str, int& pathLength, bool* visited)
{
if(str[pathLength] == '\0')
return true;

bool hasPath = false;
if(row >= 0 && row < rows && col >= 0 && col < cols
&& matrix[row * cols + col] == str[pathLength]
&& !visited[row * cols + col])
{
++pathLength;
visited[row * cols + col] = true;

hasPath = hasPathCore(matrix, rows, cols, row, col - 1,
str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row - 1, col,
str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row, col + 1,
str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row + 1, col,
str, pathLength, visited);

if(!hasPath)
{
--pathLength;
visited[row * cols + col] = false;
}
}

return hasPath;
}
``````

### 12.机器人的运动范围

``````// 很有意思
#include <cstdio>

int movingCountCore(int threshold, int rows, int cols, int row, int col, bool* visited);
bool check(int threshold, int rows, int cols, int row, int col, bool* visited);
int getDigitSum(int number);

// 主函数
int movingCount(int threshold, int rows, int cols)
{
if(threshold < 0 || rows <= 0 || cols <= 0)
return 0;

bool *visited = new bool[rows * cols];
for(int i = 0; i < rows * cols; ++i)
visited[i] = false;

int count = movingCountCore(threshold, rows, cols,
0, 0, visited);

delete[] visited;

return count;
}

// 计算矩阵最长行走路径
int movingCountCore(int threshold, int rows, int cols, int row,
int col, bool* visited)
{
int count = 0;
if(check(threshold, rows, cols, row, col, visited))
{
visited[row * cols + col] = true;

count = 1 + movingCountCore(threshold, rows, cols,
row - 1, col, visited)
+ movingCountCore(threshold, rows, cols,
row, col - 1, visited)
+ movingCountCore(threshold, rows, cols,
row + 1, col, visited)
+ movingCountCore(threshold, rows, cols,
row, col + 1, visited);
}

return count;
}

// 检查当前点是否可以进入
bool check(int threshold, int rows, int cols, int row, int col,
bool* visited)
{
if(row >= 0 && row < rows && col >= 0 && col < cols
&& getDigitSum(row) + getDigitSum(col) <= threshold
&& !visited[row* cols + col])
return true;

return false;
}

// 检查当前点数为之和
int getDigitSum(int number)
{
int sum = 0;
while(number > 0)
{
sum += number % 10;
number /= 10;
}

return sum;
}

``````

### 13.剪绳子

``````#include <iostream>
#include <cmath>

// ====================动态规划====================
int maxProductAfterCutting_solution1(int length)
{
if(length < 2)
return 0;
if(length == 2)
return 1;
if(length == 3)
return 2;

int* products = new int[length + 1];
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3;

int max = 0;
for(int i = 4; i <= length; ++i)
{
max = 0;
for(int j = 1; j <= i / 2; ++j)
{
int product = products[j] * products[i - j];
if(max < product)
max = product;

products[i] = max;
}
}

max = products[length];
delete[] products;

return max;
}

// ====================贪婪算法====================
int maxProductAfterCutting_solution2(int length)
{
if(length < 2)
return 0;
if(length == 2)
return 1;
if(length == 3)
return 2;

// 尽可能多地减去长度为3的绳子段
int timesOf3 = length / 3;

// 当绳子最后剩下的长度为4的时候，不能再剪去长度为3的绳子段。
// 此时更好的方法是把绳子剪成长度为2的两段，因为2*2 > 3*1。
if(length - timesOf3 * 3 == 1)
timesOf3 -= 1;

int timesOf2 = (length - timesOf3 * 3) / 2;

return (int) (pow(3, timesOf3)) * (int) (pow(2, timesOf2));
}
``````

### 14.二进制中1的个数

``````#include <cstdio>

int NumberOf1_Solution1(int n)
{
int count = 0;
unsigned int flag = 1;
while (flag)
{
if (n & flag)
count++;

flag = flag << 1;
}

return count;
}

int NumberOf1_Solution2(int n)
{
int count = 0;

while (n)
{
++count;
n = (n - 1) & n;
}

return count;
}
``````

### 15.数值的k次方

``````#include <iostream>
#include <cmath>

bool g_InvalidInput = false;
bool equal(double num1, double num2);
double PowerWithUnsignedExponent(double base, unsigned int exponent);

double Power(double base, int exponent)
{
g_InvalidInput = false;

if (equal(base, 0.0) && exponent < 0)
{
g_InvalidInput = true;
return 0.0;
}

unsigned int absExponent = (unsigned int) (exponent);
if (exponent < 0)
absExponent = (unsigned int) (-exponent);

double result = PowerWithUnsignedExponent(base, absExponent);
if (exponent < 0)
result = 1.0 / result;

return result;
}

double PowerWithUnsignedExponent(double base, unsigned int exponent)
{
if (exponent == 0)
return 1;
if (exponent == 1)
return base;
// 使用右移代替除2
double result = PowerWithUnsignedExponent(base, exponent >> 1);
result *= result;
// 使用与运算判断奇偶
if ((exponent & 0x1) == 1)
result *= base;

return result;
}

// 判断两个小数是否相等不能使用==
bool equal(double num1, double num2)
{
if ((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
return true;
else
return false;
}
``````

### 16.打印1到最大的n位数

``````void Print1ToMaxOfNDigits_2(int n)
{
if (n <= 0)
return;

char* number = new char[n + 1];
number[n] = '\0';

for (int i = 0; i < 10; ++i)
{
number[0] = i + '0';
Print1ToMaxOfNDigitsRecursively(number, n, 0);
}

delete[] number;
}

void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index)
{
if (index == length - 1)
{
PrintNumber(number);
return;
}

for (int i = 0; i < 10; ++i)
{
number[index + 1] = i + '0';
Print1ToMaxOfNDigitsRecursively(number, length, index + 1);
}
}

void PrintNumber(char* number)
{
bool isBeginning0 = true;
int nLength = strlen(number);

for (int i = 0; i < nLength; ++i)
{
if (isBeginning0 && number[i] != '0')
isBeginning0 = false;

if (!isBeginning0)
{
printf("%c", number[i]);
}
}

printf("\t");
}
``````

### 17 在O(1)时间删除链表结点

``````#include <cstdio>
#include "..\Utilities\xsList.h"

{
return;

// 要删除的结点不是尾结点
if(pToBeDeleted->m_pNext != nullptr)
{
ListNode* pNext = pToBeDeleted->m_pNext;
pToBeDeleted->m_nValue = pNext->m_nValue;
pToBeDeleted->m_pNext = pNext->m_pNext;

delete pNext;
pNext = nullptr;
}
// 链表只有一个结点，删除头结点（也是尾结点）
{
delete pToBeDeleted;
pToBeDeleted = nullptr;
}
// 链表中有多个结点，删除尾结点
else
{
while(pNode->m_pNext != pToBeDeleted)
{
pNode = pNode->m_pNext;
}

pNode->m_pNext = nullptr;
delete pToBeDeleted;
pToBeDeleted = nullptr;
}
}
``````

### 18. 调整数组顺序使奇数位于偶数前面

``````#include <cstdio>

void Reorder(int *pData, unsigned int length, bool (*func)(int));
bool isEven(int n);

// ====================方法一====================
void ReorderOddEven_1(int *pData, unsigned int length)
{
if(pData == nullptr || length == 0)
return;

int *pBegin = pData;
int *pEnd = pData + length - 1;

while(pBegin < pEnd)
{
// 向后移动pBegin，直到它指向偶数
while(pBegin < pEnd && (*pBegin & 0x1) != 0)
pBegin ++;

// 向前移动pEnd，直到它指向奇数
while(pBegin < pEnd && (*pEnd & 0x1) == 0)
pEnd --;

if(pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}

// ====================方法二====================
void ReorderOddEven_2(int *pData, unsigned int length)
{
Reorder(pData, length, isEven);
}

void Reorder(int *pData, unsigned int length, bool (*func)(int))
{
if(pData == nullptr || length == 0)
return;

int *pBegin = pData;
int *pEnd = pData + length - 1;

while(pBegin < pEnd)
{
// 向后移动pBegin
while(pBegin < pEnd && !func(*pBegin))
pBegin ++;

// 向前移动pEnd
while(pBegin < pEnd && func(*pEnd))
pEnd --;

if(pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}

bool isEven(int n)
{
return (n & 1) == 0;
}

``````

### 22.链表中倒数第k个结点

``````#include <cstdio>
#include "..\Utilities\List.h"

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
{
if(pListHead == nullptr || k == 0)
return nullptr;

ListNode *pBehind = nullptr;

for(unsigned int i = 0; i < k - 1; ++ i)
{
else
{
return nullptr;
}
}

{
pBehind = pBehind->m_pNext;
}

return pBehind;
}
``````

### 23.链表中环的入口结点

``````#include <cstdio>
#include "../Utilities/list.h"

{
return nullptr;

if(pSlow == nullptr)
return nullptr;

ListNode* pFast = pSlow->m_pNext;
while(pFast != nullptr && pSlow != nullptr)
{
if(pFast == pSlow)
return pFast;

pSlow = pSlow->m_pNext;

pFast = pFast->m_pNext;
if(pFast != nullptr)
pFast = pFast->m_pNext;
}

return nullptr;
}

{
if(meetingNode == nullptr)
return nullptr;

// 得到环中结点的数目
int nodesInLoop = 1;
ListNode* pNode1 = meetingNode;
while(pNode1->m_pNext != meetingNode)
{
pNode1 = pNode1->m_pNext;
++nodesInLoop;
}

// 先移动pNode1，次数为环中结点的数目
for(int i = 0; i < nodesInLoop; ++i)
pNode1 = pNode1->m_pNext;

// 再移动pNode1和pNode2
while(pNode1 != pNode2)
{
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}

return pNode1;
}
``````

### 24.反转链表

``````#include <cstdio>
#include "..\Utilities\List.h"

{
ListNode* pPrev = nullptr;
while(pNode != nullptr)
{
ListNode* pNext = pNode->m_pNext;

if(pNext == nullptr)

pNode->m_pNext = pPrev;

pPrev = pNode;
pNode = pNext;
}

}
``````

### 25.合并两个排序的链表

``````#include <cstdio>
#include "..\Utilities\List.h"

{

{
}
else
{
}

}
``````

### 26.树的子结构

``````#include <cstdio>

struct BinaryTreeNode
{
double                 m_dbValue;
BinaryTreeNode*        m_pLeft;
BinaryTreeNode*        m_pRight;
};

bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2);
bool Equal(double num1, double num2);

bool HasSubtree(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
bool result = false;

if(pRoot1 != nullptr && pRoot2 != nullptr)
{
if(Equal(pRoot1->m_dbValue, pRoot2->m_dbValue))
result = DoesTree1HaveTree2(pRoot1, pRoot2);
if(!result)
result = HasSubtree(pRoot1->m_pLeft, pRoot2);
if(!result)
result = HasSubtree(pRoot1->m_pRight, pRoot2);
}

return result;
}

bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
if(pRoot2 == nullptr)
return true;

if(pRoot1 == nullptr)
return false;

if(!Equal(pRoot1->m_dbValue, pRoot2->m_dbValue))
return false;

return DoesTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) &&
DoesTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight);
}

bool Equal(double num1, double num2)
{
if((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
return true;
else
return false;
}
``````

### 27.二叉树的镜像

``````#include <cstdio>
#include "..\Utilities\BinaryTree.h"
#include <stack>

void MirrorRecursively(BinaryTreeNode *pNode)
{
if((pNode == nullptr) || (pNode->m_pLeft == nullptr && pNode->m_pRight))
return;

BinaryTreeNode *pTemp = pNode->m_pLeft;
pNode->m_pLeft = pNode->m_pRight;
pNode->m_pRight = pTemp;

if(pNode->m_pLeft)
MirrorRecursively(pNode->m_pLeft);

if(pNode->m_pRight)
MirrorRecursively(pNode->m_pRight);
}

void MirrorIteratively(BinaryTreeNode* pRoot)
{
if(pRoot == nullptr)
return;

std::stack<BinaryTreeNode*> stackTreeNode;
stackTreeNode.push(pRoot);

while(stackTreeNode.size() > 0)
{
BinaryTreeNode *pNode = stackTreeNode.top();
stackTreeNode.pop();

BinaryTreeNode *pTemp = pNode->m_pLeft;
pNode->m_pLeft = pNode->m_pRight;
pNode->m_pRight = pTemp;

if(pNode->m_pLeft)
stackTreeNode.push(pNode->m_pLeft);

if(pNode->m_pRight)
stackTreeNode.push(pNode->m_pRight);
}
}
``````

### 28.对称的二叉树

``````#include <cstdio>
#include "../Utilities/BinaryTree.h"

bool isSymmetrical(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2);

bool isSymmetrical(BinaryTreeNode* pRoot)
{
return isSymmetrical(pRoot, pRoot);
}

bool isSymmetrical(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
if(pRoot1 == nullptr && pRoot2 == nullptr)
return true;

if(pRoot1 == nullptr || pRoot2 == nullptr)
return false;

if(pRoot1->m_nValue != pRoot2->m_nValue)
return false;

return isSymmetrical(pRoot1->m_pLeft, pRoot2->m_pRight)
&& isSymmetrical(pRoot1->m_pRight, pRoot2->m_pLeft);
}

``````

### 29.顺时针打印矩阵

``````#include <cstdio>

void PrintMatrixInCircle(int** numbers, int columns, int rows, int start);
void printNumber(int number);

void PrintMatrixClockwisely(int** numbers, int columns, int rows)
{
if(numbers == nullptr || columns <= 0 || rows <= 0)
return;

int start = 0;

while(columns > start * 2 && rows > start * 2)
{
PrintMatrixInCircle(numbers, columns, rows, start);

++start;
}
}

void PrintMatrixInCircle(int** numbers, int columns, int rows, int start)
{
int endX = columns - 1 - start;
int endY = rows - 1 - start;

// 从左到右打印一行
for(int i = start; i <= endX; ++i)
{
int number = numbers[start][i];
printNumber(number);
}

// 从上到下打印一列
if(start < endY)
{
for(int i = start + 1; i <= endY; ++i)
{
int number = numbers[i][endX];
printNumber(number);
}
}

// 从右到左打印一行
if(start < endX && start < endY)
{
for(int i = endX - 1; i >= start; --i)
{
int number = numbers[endY][i];
printNumber(number);
}
}

// 从下到上打印一行
if(start < endX && start < endY - 1)
{
for(int i = endY - 1; i >= start + 1; --i)
{
int number = numbers[i][start];
printNumber(number);
}
}
}

void printNumber(int number)
{
printf("%d\t", number);
}
``````

### 30.包含min函数的栈

``````#include <stack>
#include <assert.h>

template <typename T> class StackWithMin
{
public:
StackWithMin() {}
virtual ~StackWithMin() {}

T& top();
const T& top() const;

void push(const T& value);
void pop();

const T& min() const;

bool empty() const;
size_t size() const;

private:
std::stack<T>   m_data;     // 数据栈，存放栈的所有元素
std::stack<T>   m_min;      // 辅助栈，存放栈的最小元素
};

template <typename T> void StackWithMin<T>::push(const T& value)
{
// 把新元素添加到辅助栈
m_data.push(value);

// 当新元素比之前的最小元素小时，把新元素插入辅助栈里；
// 否则把之前的最小元素重复插入辅助栈里
if(m_min.size() == 0 || value < m_min.top())
m_min.push(value);
else
m_min.push(m_min.top());
}

template <typename T> void StackWithMin<T>::pop()
{
assert(m_data.size() > 0 && m_min.size() > 0);

m_data.pop();
m_min.pop();
}

template <typename T> const T& StackWithMin<T>::min() const
{
assert(m_data.size() > 0 && m_min.size() > 0);

return m_min.top();
}

template <typename T> T& StackWithMin<T>::top()
{
return m_data.top();
}

template <typename T> const T& StackWithMin<T>::top() const
{
return m_data.top();
}

template <typename T> bool StackWithMin<T>::empty() const
{
return m_data.empty();
}

template <typename T> size_t StackWithMin<T>::size() const
{
return m_data.size();
}
``````

### 32 不分行从上往下打印二叉树

``````#include <cstdio>
#include "..\Utilities\BinaryTree.h"
#include <deque>

void PrintFromTopToBottom(BinaryTreeNode* pRoot)
{
if(pRoot == nullptr)
return;

std::deque<BinaryTreeNode *> dequeTreeNode;

dequeTreeNode.push_back(pRoot);

while(dequeTreeNode.size())
{
BinaryTreeNode *pNode = dequeTreeNode.front();
dequeTreeNode.pop_front();

printf("%d ", pNode->m_nValue);

if(pNode->m_pLeft)
dequeTreeNode.push_back(pNode->m_pLeft);

if(pNode->m_pRight)
dequeTreeNode.push_back(pNode->m_pRight);
}
}
``````

### 33.二叉搜索树的后序遍历序列

``````#include <cstdio>

// BST：Binary Search Tree，二叉搜索树
bool VerifySquenceOfBST(int sequence[], int length)
{
if(sequence == nullptr || length <= 0)
return false;

int root = sequence[length - 1];

// 在二叉搜索树中左子树的结点小于根结点
int i = 0;
for(; i < length - 1; ++ i)
{
if(sequence[i] > root)
break;
}

// 在二叉搜索树中右子树的结点大于根结点
int j = i;
for(; j < length - 1; ++ j)
{
if(sequence[j] < root)
return false;
}

// 判断左子树是不是二叉搜索树
bool left = true;
if(i > 0)
left = VerifySquenceOfBST(sequence, i);

// 判断右子树是不是二叉搜索树
bool right = true;
if(i < length - 1)
right = VerifySquenceOfBST(sequence + i, length - i - 1);

return (left && right);
}
``````

### 34 二叉树中和为某一值的路径

``````#include <cstdio>
#include "..\Utilities\BinaryTree.h"
#include <vector>

void FindPath(BinaryTreeNode* pRoot, int expectedSum, std::vector<int>& path, int& currentSum);

void FindPath(BinaryTreeNode* pRoot, int expectedSum)
{
if(pRoot == nullptr)
return;

std::vector<int> path;
int currentSum = 0;
FindPath(pRoot, expectedSum, path, currentSum);
}

void FindPath
(
BinaryTreeNode*   pRoot,
int               expectedSum,
std::vector<int>& path,
int&              currentSum
)
{
currentSum += pRoot->m_nValue;
path.push_back(pRoot->m_nValue);

// 如果是叶结点，并且路径上结点的和等于输入的值
// 打印出这条路径
bool isLeaf = pRoot->m_pLeft == nullptr && pRoot->m_pRight == nullptr;
if(currentSum == expectedSum && isLeaf)
{
printf("A path is found: ");
std::vector<int>::iterator iter = path.begin();
for(; iter != path.end(); ++ iter)
printf("%d\t", *iter);

printf("\n");
}

// 如果不是叶结点，则遍历它的子结点
if(pRoot->m_pLeft != nullptr)
FindPath(pRoot->m_pLeft, expectedSum, path, currentSum);
if(pRoot->m_pRight != nullptr)
FindPath(pRoot->m_pRight, expectedSum, path, currentSum);

// 在返回到父结点之前，在路径上删除当前结点，
// 并在currentSum中减去当前结点的值
currentSum -= pRoot->m_nValue;
path.pop_back();
}

``````

### 36.二叉搜索树与双向链表

``````#include <cstdio>
#include "..\Utilities\BinaryTree.h"

void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList);

BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{
BinaryTreeNode *pLastNodeInList = nullptr;
ConvertNode(pRootOfTree, &pLastNodeInList);

// pLastNodeInList指向双向链表的尾结点，
// 我们需要返回头结点

}

void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
{
if(pNode == nullptr)
return;

BinaryTreeNode *pCurrent = pNode;

if (pCurrent->m_pLeft != nullptr)
ConvertNode(pCurrent->m_pLeft, pLastNodeInList);

pCurrent->m_pLeft = *pLastNodeInList;
if(*pLastNodeInList != nullptr)
(*pLastNodeInList)->m_pRight = pCurrent;

*pLastNodeInList = pCurrent;

if (pCurrent->m_pRight != nullptr)
ConvertNode(pCurrent->m_pRight, pLastNodeInList);
}
``````

### 38 字符串的全排列

``````#include <cstdio>

void Permutation(char* pStr, char* pBegin);

void Permutation(char* pStr)
{
if(pStr == nullptr)
return;

Permutation(pStr, pStr);
}

void Permutation(char* pStr, char* pBegin)
{
if(*pBegin == '\0')
{
printf("%s\n", pStr);
}
else
{
for(char* pCh = pBegin; *pCh != '\0'; ++ pCh)
{
char temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;

Permutation(pStr, pBegin + 1);

temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
}
}
}
``````

### 39.数组中出现次数超过一半的数字

``````#include <cstdio>
#include "..\Utilities\Array.h"

bool g_bInputInvalid = false;

bool CheckInvalidArray(int* numbers, int length)
{
g_bInputInvalid = false;
if(numbers == nullptr && length <= 0)
g_bInputInvalid = true;

return g_bInputInvalid;
}

bool CheckMoreThanHalf(int* numbers, int length, int number)
{
int times = 0;
for(int i = 0; i < length; ++i)
{
if(numbers[i] == number)
times++;
}

bool isMoreThanHalf = true;
if(times * 2 <= length)
{
g_bInputInvalid = true;
isMoreThanHalf = false;
}

return isMoreThanHalf;
}
``````

### 40.最小的k个数

``````#include <cstdio>
#include "..\Utilities\Array.h"

#include <set>
#include <vector>
#include <iostream>
#include <functional>

using namespace std;

// ====================方法1====================
void GetLeastNumbers_Solution1(int* input, int n, int* output, int k)
{
if(input == nullptr || output == nullptr || k > n || n <= 0 || k <= 0)
return;

int start = 0;
int end = n - 1;
int index = Partition(input, n, start, end);
while(index != k - 1)
{
if(index > k - 1)
{
end = index - 1;
index = Partition(input, n, start, end);
}
else
{
start = index + 1;
index = Partition(input, n, start, end);
}
}

for(int i = 0; i < k; ++i)
output[i] = input[i];
}

// ====================方法2====================
typedef multiset<int, std::greater<int> >            intSet;
typedef multiset<int, std::greater<int> >::iterator  setIterator;

void GetLeastNumbers_Solution2(const vector<int>& data, intSet& leastNumbers, int k)
{
leastNumbers.clear();

if(k < 1 || data.size() < k)
return;

vector<int>::const_iterator iter = data.begin();
for(; iter != data.end(); ++ iter)
{
if((leastNumbers.size()) < k)
leastNumbers.insert(*iter);

else
{
setIterator iterGreatest = leastNumbers.begin();

if(*iter < *(leastNumbers.begin()))
{
leastNumbers.erase(iterGreatest);
leastNumbers.insert(*iter);
}
}
}
}
``````

### 42.连续子数组的最大和

``````#include <cstdio>

bool g_InvalidInput = false;

int FindGreatestSumOfSubArray(int *pData, int nLength)
{
if((pData == nullptr) || (nLength <= 0))
{
g_InvalidInput = true;
return 0;
}

g_InvalidInput = false;

int nCurSum = 0;
int nGreatestSum = 0x80000000;
for(int i = 0; i < nLength; ++i)
{
if(nCurSum <= 0)
nCurSum = pData[i];
else
nCurSum += pData[i];

if(nCurSum > nGreatestSum)
nGreatestSum = nCurSum;
}

return nGreatestSum;
}
``````

### 50.字符串中第一个只出现一次的字符

``````#include <cstdio>
#include <string>

char FirstNotRepeatingChar(const char* pString)
{
if(pString == nullptr)
return '\0';

const int tableSize = 256;
unsigned int hashTable[tableSize];
for(unsigned int i = 0; i < tableSize; ++i)
hashTable[i] = 0;

const char* pHashKey = pString;
while(*(pHashKey) != '\0')
hashTable[*(pHashKey++)] ++;

pHashKey = pString;
while(*pHashKey != '\0')
{
if(hashTable[*pHashKey] == 1)
return *pHashKey;

pHashKey++;
}

return '\0';
}
``````

### 52.两个链表的第一个公共结点

``````#include <cstdio>
#include "..\Utilities\List.h"

{
// 得到两个链表的长度
int nLengthDif = nLength1 - nLength2;

if(nLength2 > nLength1)
{
nLengthDif = nLength2 - nLength1;
}

// 先在长链表上走几步，再同时在两个链表上遍历
for(int i = 0; i < nLengthDif; ++i)

{
}

// 得到第一个公共结点

return pFisrtCommonNode;
}

{
unsigned int nLength = 0;
while(pNode != nullptr)
{
++nLength;
pNode = pNode->m_pNext;
}

return nLength;
}
``````

### 53.在排序数组中查找数字

``````#include <cstdio>

int GetFirstK(const int* data, int length, int k, int start, int end);
int GetLastK(const int* data, int length, int k, int start, int end);

int GetNumberOfK(const int* data, int length, int k)
{
int number = 0;

if(data != nullptr && length > 0)
{
int first = GetFirstK(data, length, k, 0, length - 1);
int last = GetLastK(data, length, k, 0, length - 1);

if(first > -1 && last > -1)
number = last - first + 1;
}

return number;
}

// 找到数组中第一个k的下标。如果数组中不存在k，返回-1
int GetFirstK(const int* data, int length, int k, int start, int end)
{
if(start > end)
return -1;

int middleIndex = (start + end) / 2;
int middleData = data[middleIndex];

if(middleData == k)
{
if((middleIndex > 0 && data[middleIndex - 1] != k)
|| middleIndex == 0)
return middleIndex;
else
end  = middleIndex - 1;
}
else if(middleData > k)
end = middleIndex - 1;
else
start = middleIndex + 1;

return GetFirstK(data, length, k, start, end);
}

// 找到数组中最后一个k的下标。如果数组中不存在k，返回-1
int GetLastK(const int* data, int length, int k, int start, int end)
{
if(start > end)
return -1;

int middleIndex = (start + end) / 2;
int middleData = data[middleIndex];

if(middleData == k)
{
if((middleIndex < length - 1 && data[middleIndex + 1] != k)
|| middleIndex == length - 1)
return middleIndex;
else
start  = middleIndex + 1;
}
else if(middleData < k)
start = middleIndex + 1;
else
end = middleIndex - 1;

return GetLastK(data, length, k, start, end);
}
``````

``````#include <cstdio>

int GetMissingNumber(const int* numbers, int length)
{
if(numbers == nullptr || length <= 0)
return -1;

int left = 0;
int right = length - 1;
while(left <= right)
{
int middle = (right + left) >> 1;
if(numbers[middle] != middle)
{
if(middle == 0 || numbers[middle - 1] == middle - 1)
return middle;
right = middle - 1;
}
else
left = middle + 1;
}

if(left == length)
return length;

// 无效的输入，比如数组不是按要求排序的，
// 或者有数字不在0到n-1范围之内
return -1;
}
``````

``````#include <cstdio>

int GetNumberSameAsIndex(const int* numbers, int length)
{
if(numbers == nullptr || length <= 0)
return -1;

int left = 0;
int right = length - 1;
while(left <= right)
{
int middle = left + ((right - left) >> 1);
if(numbers[middle] == middle)
return middle;

if(numbers[middle] > middle)
right = middle - 1;
else
left = middle + 1;
}

return -1;
}
``````

### 54.二叉搜索树的第k个结点

``````#include <cstdio>
#include "../Utilities/BinaryTree.h"

const BinaryTreeNode* KthNodeCore(const BinaryTreeNode* pRoot, unsigned int& k);

const BinaryTreeNode* KthNode(const BinaryTreeNode* pRoot, unsigned int k)
{
if(pRoot == nullptr || k == 0)
return nullptr;

return KthNodeCore(pRoot, k);
}

const BinaryTreeNode* KthNodeCore(const BinaryTreeNode* pRoot, unsigned int& k)
{
const BinaryTreeNode* target = nullptr;

if(pRoot->m_pLeft != nullptr)
target = KthNodeCore(pRoot->m_pLeft, k);

if(target == nullptr)
{
if(k == 1)
target = pRoot;

k--;
}

if(target == nullptr && pRoot->m_pRight != nullptr)
target = KthNodeCore(pRoot->m_pRight, k);

return target;
}
``````

### 55.二叉树的深度

``````#include <cstdio>
#include "..\Utilities\BinaryTree.h"

int TreeDepth(const BinaryTreeNode* pRoot)
{
if(pRoot == nullptr)
return 0;

int nLeft = TreeDepth(pRoot->m_pLeft);
int nRight = TreeDepth(pRoot->m_pRight);

return (nLeft > nRight) ? (nLeft + 1) : (nRight + 1);
}
``````

### 57.和为s的两个数字

1. 依次遍历，对于第一个数x，在后面找target-x；
2. 利用hashmap，对于数x，在map里找是否存在target-x；
3. 双指针法：初始一个指针在第一个数字，第二个指针在末尾的数字。两个数字相加，如果和大于target，则高指针下移。如果和小于target。则低指针上移。直到两个指针相遇。
``````#include <cstdio>

bool FindNumbersWithSum(int data[], int length, int sum,
int* num1, int* num2)
{
bool found = false;
if(length < 1 || num1 == nullptr || num2 == nullptr)
return found;

int ahead = length - 1;
int behind = 0;

{
long long curSum = data[ahead] + data[behind];

if(curSum == sum)
{
*num1 = data[behind];
found = true;
break;
}
else if(curSum > sum)
else
behind ++;
}

return found;
}

``````

threesum：调用之前twosum的接口，把数组分为两部分，一个是第一个数字x，一个剩余部分，在剩余部分找target-x的twosum。之后右移动第一个数字，且跳过所有相同的，继续分割数组，在剩余数组内找twosum

``````#include <cstdio>

void PrintContinuousSequence(int small, int big);

void FindContinuousSequence(int sum)
{
if(sum < 3)
return;

int small = 1;
int big = 2;
int middle = (1 + sum) / 2;
int curSum = small + big;

while(small < middle)
{
if(curSum == sum)
PrintContinuousSequence(small, big);

while(curSum > sum && small < middle)
{
curSum -= small;
small ++;

if(curSum == sum)
PrintContinuousSequence(small, big);
}

big ++;
curSum += big;
}
}

void PrintContinuousSequence(int small, int big)
{
for(int i = small; i <= big; ++ i)
printf("%d ", i);

printf("\n");
}

``````

### 58.翻转单词顺序

``````#include <cstdio>
#include "..\Utilities\StringUtil.h"
#include <string>

char* ReverseSentence(char *pData)
{
if(pData == nullptr)
return nullptr;

char *pBegin = pData;

char *pEnd = pData;
while(*pEnd != '\0')
pEnd ++;
pEnd--;

// 翻转整个句子
Reverse(pBegin, pEnd);

// 翻转句子中的每个单词
pBegin = pEnd = pData;
while(*pBegin != '\0')
{
if(*pBegin == ' ')
{
pBegin ++;
pEnd ++;
}
else if(*pEnd == ' ' || *pEnd == '\0')
{
Reverse(pBegin, --pEnd);
pBegin = ++pEnd;
}
else
pEnd ++;
}

return pData;
}
``````

``````#include <cstdio>
#include "..\Utilities\StringUtil.h"
#include <string.h>

char* LeftRotateString(char* pStr, int n)
{
if(pStr != nullptr)
{
int nLength = static_cast<int>(strlen(pStr));
if(nLength > 0 && n > 0 && n < nLength)
{
char* pFirstStart = pStr;
char* pFirstEnd = pStr + n - 1;
char* pSecondStart = pStr + n;
char* pSecondEnd = pStr + nLength - 1;

// 翻转字符串的前面n个字符
Reverse(pFirstStart, pFirstEnd);
// 翻转字符串的后面部分
Reverse(pSecondStart, pSecondEnd);
// 翻转整个字符串
Reverse(pFirstStart, pSecondEnd);
}
}

return pStr;
}
``````

### 60.n个骰子的点数

n个骰子的点数，可以先把骰分成两堆，第一堆只有一个，第二堆n-1个，单独那一个有可能出现1-6的点数。我们需要计算1-6每一个点数和剩下的n-1个骰子计算点数和。接下来继续把剩下的n-1个骰子分成两部分，一堆只有一个，另一堆n-2个，把上一轮的点数和这一轮相加，再计算
n-2个的情况，直到还是最后一个。这就是一个递归的思路。

``````#include <cstdio>
#include <math.h>

int g_maxValue = 6;

// ====================方法一====================
void Probability(int number, int* pProbabilities);
void Probability(int original, int current, int sum, int* pProbabilities);

void PrintProbability_Solution1(int number)
{
if(number < 1)
return;

int maxSum = number * g_maxValue;
int* pProbabilities = new int[maxSum - number + 1];
for(int i = number; i <= maxSum; ++i)
pProbabilities[i - number] = 0;

Probability(number, pProbabilities);

int total = pow((double)g_maxValue, number);
for(int i = number; i <= maxSum; ++i)
{
double ratio = (double)pProbabilities[i - number] / total;
printf("%d: %e\n", i, ratio);
}

delete[] pProbabilities;
}

void Probability(int number, int* pProbabilities)
{
for(int i = 1; i <= g_maxValue; ++i)
Probability(number, number, i, pProbabilities);
}

void Probability(int original, int current, int sum,
int* pProbabilities)
{
if(current == 1)
{
pProbabilities[sum - original]++;
}
else
{
for(int i = 1; i <= g_maxValue; ++i)
{
Probability(original, current - 1, i + sum, pProbabilities);
}
}
}

``````

### 62.圆圈中最后剩下的数字

``````#include <cstdio>
#include <list>

using namespace std;

// ====================方法1====================
int LastRemaining_Solution1(unsigned int n, unsigned int m)
{
if(n < 1 || m < 1)
return -1;

unsigned int i = 0;

list<int> numbers;
for(i = 0; i < n; ++ i)
numbers.push_back(i);

list<int>::iterator current = numbers.begin();
while(numbers.size() > 1)
{
for(int i = 1; i < m; ++ i)
{
current ++;
if(current == numbers.end())
current = numbers.begin();
}

list<int>::iterator next = ++ current;
if(next == numbers.end())
next = numbers.begin();

-- current;
numbers.erase(current);
current = next;
}

return *(current);
}
``````

### 63.股票的最大利润

``````#include <cstdio>

int MaxDiff(const int* numbers, unsigned length)
{
if(numbers == nullptr && length < 2)
return 0;

int min = numbers[0];
int maxDiff = numbers[1] - min;

for(int i = 2; i < length; ++i)
{
if(numbers[i - 1] < min)
min = numbers[i - 1];

int currentDiff = numbers[i] - min;
if(currentDiff > maxDiff)
maxDiff = currentDiff;
}

return maxDiff;
}
``````

## 其它(from zuochengyun live)

### 3.关于sort()函数

sort(A), size(A)=N;

1. 如果n<60，直接插入排序。O(N^2),N较小时，平方也不大。但是常数空间O(1) (基于比较交换的排序都是)。
2. n>60;则选择快速排序和归并排序。当比较类型为基本类型时，选择快排。如果是类类型时，选择归并排序。

### 4.一个无序数组输出其排序后相邻差值最大的差值。O(N)

1. 0(N)的复杂度就要求我们不能进行普通排序，我们可以进行桶排序。
2.遍历一次数组，得到最大值和最小值[x,y]，以及数组长度N，则设立N+1个桶(等分[x,y])，把N个数塞入N+1个桶，则至少有一个空桶。该空桶前一个桶的最大值和后一个桶的最小值差值大于一个桶的范围。所以我们找最大差值时不需要考虑桶内的情况。

### 5.用数组实现队列

1.用两个指针，end表示从那个位置入队，start表示从哪个位置出队。end和start初始都在数组开头，两者无关。但是设立size值，表示当前队列长度。当size为N时，end回到数组开头，不可以入队。size只要不为0，start就可以动。

### 推荐阅读更多精彩内容

• 栈 1. 栈（stack）又名堆栈，它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被...
IT程序员阅读 2,736评论 0 6
• pdf下载地址：Java面试宝典 第一章内容介绍 20 第二章JavaSE基础 21 一、Java面向对象 21 ...
王震阳阅读 73,523评论 25 504
• 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系，并对这种结构定义相应的运算，而且确保经过这...
Winterfell_Z阅读 1,016评论 0 4
• 1.把二元查找树转变成排序的双向链表题目：输入一棵二元查找树，将该二元查找树转换成一个排序的双向链表。要求不能创建...
锐心凌志阅读 2,215评论 0 24
• 前言 2. 实现 Singleton 3. 数组中重复的数字 4. 二维数组中的查找 5. 替换空格 6. 从尾到...
Observer_____阅读 1,339评论 0 2