第4章 解决面试题的思路
4.1 面试官谈面试思路 编码之前先讲自己的思路。4.2 画图让抽象问题形象化 图形能使抽象的问题具体化,形象化。题目19:二叉树的镜像题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。二叉树结点的定义如下:
struct BinaryTreeNode {int m_nValue;BinaryTreeNode* m_pLeft;BinaryTreeNode* m_pRight;
};思路:先前序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子结点。当交换完所有非叶子结点的左右子结点之后,就得到了树的镜像。void MirrorRecursively(BinaryTreeNode* pNode)
{if (pNode == null) {return;}if (pNode->m_pLeft == null && pNode->m_pRight == null) {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);}
}面试题20:顺时针打印矩阵题目:输入一个矩阵,按照从外往里以顺时针的顺序依次打印出每一个数字。例如:如果输入如下矩阵:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16则依次打印出 1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10分析循环条件:假设这个矩阵的行数是rows,列数是columns。打印第一圈的左上角的坐标是(0,0),第二圈左上角的坐标是(1,1),以此类推。我们注意到,左上角的坐标中行标和列标总是相等的,于是可以在矩阵中选取左上角(start,start)的一圈作为我们分析的目标。对于一个5*5的矩阵而言,最后一圈只有数字,对应的坐标为(2,2)。我们发现 5>2*2。对于一个6*6的矩阵而言,最后一圈有4个数字,其左上角的坐标仍为(2,2)。我们发现 6>2*2依然成立。于是我们可以得出,让循环继续的条件是 columns>startX*2并且rows>startY*2。void PrintMatrixClockwisely(int** numbers, int columns, int rows)
{if (numbers == null || columns <= 0 || rows >= 0) {return;}int start = 0;while (columns > start * 2 && rows > start * 2) {PrintMatrixInCircle(numbers, columns, rows, start);start++;}
}接着我们考虑如何打印一圈的功能,即如何实现 PrintMatrixInCircle。我们可以把打印一圈分为4步:第一步从左到右打印一行,第二步从上到下打印
一行,第三步从右到左打印一行,第四步从下到上打印一列。每一步我们根据起始坐标和终止坐标用一个循环就能打印出一行或者一列。不过值得注意的是,最后一圈可能退化成只有一行,只有一列,甚至只有一个数字,因此打印这样的一圈就不需要四步。因此我们需要分析打印时每一步的前提条件。第一步总是需要的,因为打印一圈至少有一步。如果只有一行,那么就不用第二步。也就是需要第二步的前提是
终止行号大于起始行号。需要第三步打印的前提条件是圈内至少有两行两列,也就是说除了要求终止行号大于起始行号之外,还要求终止列号大于起始列号。同理,
需要打印第四步的前提条件是至少有三行两列,因此要求终止行号比起始行号至少大2,同时终止列号大于起始列号。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);}//从上到下打印一列for (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; i--) {int number = numbers[i][start];if (start < endX && start < endY) {}}
}   4.3 举例让抽象问题具体化 面试题21:包含 min 函数的栈题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min,push及pop的时间复杂度都是O(1)。首先往空的数据栈压入数字3,显然现在3是最小值,我们也把这个值压入辅助栈。接下来往数据栈压入数字4.由于4大于之前的最小值,因此我们仍然需要往辅助栈压入数字3.
第三步继续往数据栈压入数字2。由于2小于之前的3,因此我们把最小值更新为2,并把2压入辅助栈。同样,当压入数字1时,也更新最小值,并把最新的1压入辅助栈。从上面可以看出来,如果每次都把最小元素压入辅助栈,那么就能保证辅助栈的栈顶一直是最小元素。当最小元素从数据栈里被弹出的时候,同时弹出辅助栈的栈顶元素,此时
辅助栈的新栈顶元素就是下一个最小值。//m_data 是数据栈,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();
}面试题22:栈的压入,弹出序列题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压栈
序列,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2 就不可能是该压栈序列的弹出序列。解决这个问题很直观的想法就是建立一个辅助栈,把输入的第一个序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数字。规律:如果下一个弹出的数字刚好是栈顶数字,那么直接弹出。如果下一个弹出的数字不在栈顶,我们把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止。如果所有的数字都压入了仍然没有找到下一个弹出的数字,那么该序列就不可能是一个弹出序列。// int 数组指针 pPush,pPop
bool IsPopOrder(const int* pPush, const int* pPop, int nLength)
{bool bPossible = false;if (pPush != null && pPop != null && nLength > 0) {const int* pNextPush = pPush;const int* pNextPop = pPop;std::stack<int>stackData;while (pNextPop - pPop < nLength) {while (stackData.empty() || stackData.top() != *pNextPop) {if (pNextPush - pPush == nLength) break;stackData.push(*pNextPush);pNextPush++;}if (stackData.top() != *pNextPop)break;stackData.pop();pNextPop++;}if (stackData.empty() && pNextPop - pPop == nLength) {bPossible = true;}}return bPossible;
}面试题23:从上往下打印二叉树题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左往右的顺序打印。例如输入8,6,10,5,7,9,11(按层输入),依次打印出 8,6,10,5,7,9,11二叉树结点定义如下:
struct BinaryTreeNode {int m_nValue;BinaryTreeNode* m_pLeft;BinaryTreeNode* m_pRight;
};分析:这种考察的是树的遍历算法,只是这种遍历不是我们熟悉的 前序,中序,后序遍历。规律:每一次打印一个结点的时候,如果该结点有子节点,则把该结点的子节点放到一个队列的末尾。接下来到队列的头部取出最早进入队列的结点,重复前面的打印操作,直到队列中所有的结点都被打印出来为止。void PrintFromTopToButton(BinaryTreeNode* pTreeRoot)
{if (!pTreeRoot) return;std::deque<BinaryTreeNode*> dequeTreeNode;dequeTreeNode.push_back(pTreeRoot);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);}}
}本题扩展:如何广度遍历一个有向图?这同样也可以基于队列实现。树是图的一种特殊退化形式,从上到下按层遍历二叉树,从本质上来说就是广度优先遍历二叉树。举一反三:  不管是广度优先遍历一个有向图还是一棵树,都要用到队列。第一步我们把起始点(对树而言是根结点)放入队列中。接下来每一次从队列的头部取出一个结点,遍历这个结点之后把从它能到达的结点(对树而言是子节点)都依次放入队列。我们重复这个遍历过程,直到队列中的结点都被遍历为止。面试题24:二叉搜索树的后序遍历序列题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后续遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。分析:在后序遍历中,最后一个数字是树的根结点的值。数组中前面的数字可以分为两部分:第一部分是左子树结点的值,它们都比根结点的值小;第二部分是右子树结点的值,它们都比根结点的值大。bool VerifySquenceOfBST(int sequence[], int length)
{if (sequence == null || 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[i] < 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);
}相关题目:输入一个整数数组,判断该数组是不是某二叉搜索树的前序遍历的结果。这和前面的问题的后序遍历很相似,只是在前序遍历得到的序列中,第一个数字是根结点的值。举一反三:如果面试题要求是处理一颗二叉树的遍历序列,我们可以先找到二叉树的根结点,再基于根结点把整个树的遍历序列拆分成左子树对应的子序列和右子树对应的子序列,接下来再递归的处理这2个子序列。面试题25:二叉树中和为某一值的路径题目:输入一个二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。从树的根结点开始往下一直到叶节点所经过的结点形成一条路径。二叉树结点的定义如下:
sruct BinaryTreeNode {int m_nValue;BinaryTreeNode* m_pLeft;BinaryTreeNode* m_pRight;
};分析:当用前序遍历的方式访问到某一节点的时候,我们把该结点添加到路径上,并累加该结点的值。如果该节点是叶结点并且路径中结点值刚好等于输入的整数,则当前的路径符合要求,我们打印出来。如果当前结点不是叶结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动回到它的父结点。因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保返回父结点时路径刚好是从根结点到父结点的路径。我们不难看出保存路径的数据结构实际上是一个栈,因为路径要与递归调用的状态一致,而递归调用的本质就是一个压栈和出栈的过程。void FindPath(BinaryTreeNode* pRoot, int expectedSum)
{if (pRoot == null) 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 == null && pRoot->m_pRight == null;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 != null) {FindPath(pRoot->m_pLeft, expectedSum, path, currentSum);}if (pRoot->m_pRight != null) {FindPath(pRoot->m_pRight, expectedSum, path, currentSum);}//返回到父结点之前,在路径上删除当前结点path.pop_back();
}4.4 分解让复杂问题简单化 面试题26:复杂链表的复制题目:请实现函数 ComplexListNode* Clone(ComplexListNode* pHead) 复制一个复杂的链表。在复杂链表中,每个结点除了有一个m_pNext 指针指向下一个结点外,还有一个m_pSibling 指向链表中的任意结点或者 null。结点的C++定义如下:
struct ComplexListNode {int m_nValue;ComplexListNode* m_pNext;ComplexListNode* m_pSibling;
};注:复杂链表的结点中,除了有指向下一个结点的指针,还有指向任意结点的指针。第一种方法:第一步是复制原始链表上的每个结点,并用m_pNext连接起来;第二步是设置每个结点的m_pSibling指针。假设原始链表中的某个结点N的m_pSibling指向结点S,由于S的位置在链表中可能在N前面也可能在N的后面,所以要定位S的位置需要从原始链表的头结点开始找。对于一个含有n个结点的链表,由于定位每个结点的m_pSibling 都需要从链表头结点开始经过O(n)步才能找到,时间复杂度是O(n^2)。第二种方法:第一步还是复制原始链表上的每个结点N创建N1,然后把这些创建出来的结点用m_pNext链接起来。同时我们把<N,N1>的配对信息放到一个哈希表中。第二步还是设置复制链表上每个结点的m_pSibling。如果在原始链表中结点N的m_pSibling指向结点S,那么在复制链表中,对应的N1应该指向S1。由于有了哈希表,我们可以用O(1)的时间根据S找到S1。这种相当于时间换空间。第三种方法:第一步仍然是根据原始链表的每个结点N创建对应的N1。这一次,我们把N1链接放在N的后面。第二步,设置复制出来的结点m_pSibling。第三步,把这个长链表拆分成两个链表:把奇数位置的结点用 m_pNext 链接起来就是原始链表,把偶数位置的结点用 m_pNext 链接起来就是复制出来的链表。ComplexListNode* Clone(ComplexListNode* pHead)
{CloneNodes(pHead);ConnectSiblingNodes(pHead);return ReconnectNodes(pHead);
}void CloneNodes(ComplexListNode* pHead)
{ComplexListNode* pNode = pHead;while (pNode != null) {ComplexListNode* pCloned = new ComplexListNode();pCloned->m_nValue = pNode->m_nValue;pCloned->m_pNext = pNode->m_pNext;pCloned->m_pSibing = null;pNode->m_pNext = pCloned;pNode = pCloned->m_pNext;}
}void ConnectSiblingNodes(ComplexListNode* pHead)
{ComplexListNode* pNode = pHead;while (pNode != null) {ComplexListNode* pCloned = pNode->m_pNext;if (pNode->m_pSibling != null) {pCloned->m_pSibling = pNode->m_pSibling->m_pNext;}pNode = pCloned->m_pNext;}
}void ReconnectNodes(ComplexListNode* pHead)
{ComplexListNode* pNode = pHead;ComplexListNode* pClonedHead = null;ComplexListNode* pClonedNode = null;if (pNode != null) {pClonedHead = pClonedNode = pNode->m_pNext;pNode->m_pNext = pClonedNode->m_pNext;pNode = pNode->m_pNext;}while (pNode != null) {pClonedNode->m_pNext = pNode->m_pNext;pClonedNode = pClonedNode->m_pNext;pNode->m_pNext = pClonedNode->m_pNext;pNode = pNode->m_pNext;}return pClonedHead;
}面试题27:二叉搜索树与双向链表题目:输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整该树中结点指针的指向。二叉树结点定义如下:
struct BinaryTreeNode {int m_nValue;BinaryTreeNode* m_pLeft;BinaryTreeNode* m_pRight;
};分析:在二叉搜索树中,左子节点的值总是小于父结点的值,右子结点的值总是大于父结点的值。因此我们在转换成排序双向链表的时候,原先指向左子节点的指针调整为链表中指向前一个结点的指针,原先指向右子结点的指针调整为链表中指向后一个节点的指针。BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{BinaryTreeNode* pLastNodeInList;ConvertNode(pRootOfTree, &pLastNodeInList);//pLastNodeInList指向双向链表的尾结点;我们需要返回头结点BinaryTreeNode* pHeadOfList = pLastNodeInList;while (pHeadOfList != null && pHeadOfList->m_pLeft != null) {pHeadOfList = pHeadOfList->m_pLeft;}return pHeadOfList;
}void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
{if (pNode == null)return;BinaryTreeNode* pCurrent = pNode;if (pCurrent->m_pLeft != null) {ConvertNode(pCurrent->m_pLeft, pLastNodeInLast);}pCurrent->m_pLeft = *pLastNodeInList;if (*pLastNodeInList != null) {(*pLastNodeInList)->m_pRight = pCurrent;}*pLastNodeInList = pCurrent;if (pCurrent->m_pRight != null) {ConvertNode(pCurrent->m_pRight, pLastNodeInList);}
}面试题28:字符串的排列题目:输入一个字符串,打印出该字符串中字符的所有排序。例如输入字符串 "abc",则打印出字符a,b,c 所能排列出来的所有字符串 abc,acb,bac,bca,cab,cba。分析:把复杂的问题分解成小问题。比如,我们把第一个字符串看成两部分组成:第一部分为它的第一个字符,第二部分是后面所有字符。我们求整个字符串的排列,可以看成两步:首先求所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换。第二步固定第一个字符,求后面所有字符的排列。这个时候我们仍把后面的所有字符分成两个部分。void Permutation(char* pStr)
{if (pStr == null)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;}}
}在函数  Permutation(char* pStr, char* pBegin) 中,指针pStr指向整个字符串的第一个字符,pBegin 指向当前我们做排列操作的字符串的第一个字符。在每一次
递归的时候,我们从 pBegin 向后扫描每一个字符(即指针 pCh 指向的字符)。在交换 pBegin 和 pCh 指向的字符后,我们再对 pBegin 后面的字符串递归的做排列操作,直至
pBegin 指向字符串的末尾。本题扩展:如果不是要求字符的所有排列,而是字符的所有组合,应该怎么办?输入a,b,c, 则它的组合有 a,b,c,ab,ac,bc,abc。当交换字符串中的两个字符时,虽然能得到两个不同的排列,但却是同一个组合。比如ab和ba是不同的排列,但只算一个组合。如果输入n个字符,则这n个字符能构成长度为1的组合,长度为2的组合,... 长度为n的组合。在求n个字符的长度为m(1<= m <= n)的组合的时候,我们把这n个字符分成2个部分:第一个字符和其余所有的字符。如果组合里面包含第一个字符,则下一步在剩余的字符里选取 m - 1 个字符;如果组合里不包含第一个字符,则下一步在剩余的 n - 1个字符里面选取m个字符。也就是说,我们可以把求n个字符组成长度为m的组合的问题分解成两个子问题,分别求n-1个字符串长度为m-1的组合,以及求n-1个字符的长度为m的组合,这两个子问题都可以用递归的方式解决。相关题目:1.输入一个含有8个数字的数组,判断有没有可能把这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。2.在8*8的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后不能处在同一行,同一列或者同一对角线上。请问总共有多少种符合条件的摆法?举一反三:如果面试题是按照一定要求摆放若干个数字,我们可以先求出这些数字的所有排列,然后再一一判断每个排列是不是满足题目给定的要求。

4.剑指Offer --- 解决面试题的思路相关推荐

  1. 二叉树代码 java面试题_《剑指offer》面试题39 二叉树的深度(java)

    摘要: 今天翻到了<剑指offer>面试题39,题目二中的解法二是在函数的参数列表中通过指针的方式进行传值,而java是没有指针的,所以函数要进行改造.然而我翻了下别人的java版本(我就 ...

  2. 剑指Offer——迅雷笔试题+知识点总结

    剑指Offer--迅雷笔试题+知识点总结 情景回顾 时间:2016.9.19 19:00-21:00 地点:山东省网络环境智能计算技术重点实验室 事件:迅雷笔试 总体来说,迅雷笔试内容体量不算多,主要 ...

  3. 《剑指Offer》面试题四(牛客网在线编程第一题):二维数组中的查找(Java实现)

    题目:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. ...

  4. 《剑指offer》面试题的Python实现

    所属网站分类: 面试经典 > python 作者:gg 链接: http://www.pythonheidong.com/blog/article/464/ 来源:python黑洞网 www.p ...

  5. 一道剑指offer经典面试题引发的思考

    大家在拿到一道算法题的时候,都会思考些什么呢? 大家有没有想过,当有一位面试官追问你,这道题有没有什么问题,或者有没有什么更好的方法,你们的内心是怎样的呢? 可能你会瞪大了眼,一些盲目自信的同学可能会 ...

  6. java牛客排序算法题_《剑指offer》面试题28:字符串的排列(牛客网版本) java...

    输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输入一个字符 ...

  7. 数组中其余的排除_[leetcode 剑指offer系列] 面试题04. 二维数组中的查找

    题目难度: 简单 原题链接 今天继续更新剑指 offer 系列, 这道题的优化空间非常大, 个人感觉很适合作为面试题, 值得一做. 大家在我的公众号"每日精选算法题"中的聊天框中回 ...

  8. python正则表达式面试_【剑指offer】面试题19. 正则表达式匹配

    面试题19. 正则表达式匹配 请实现一个函数用来匹配包含'. '和''的正则表达式.模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(含0次).在本题中,匹配是指字符串的所有字 ...

  9. 剑指Offer——滴滴笔试题+知识点总结

    文章目录 一.情景回顾 二.选择题 三.Linux链接 四.编程题 4.1 小青蛙走迷宫 4.2 末尾0的个数 五.简答题 六.Tomcat Server处理http请求的过程 一.情景回顾 时间:2 ...

  10. 《剑指offer》面试题1:赋值运算符函数 思考总结

    目录 题目 注意事项 相关知识点 异常安全性 bad_alloc 1.举例 2.异常处理 题目 注意事项 对于本题,正如书中所讲我们需要注意以下几点: 考虑返回值的类型:只有返回一个引用,才可以允许连 ...

最新文章

  1. Android Studio 3.0 安装注意点
  2. 电脑硬盘是干什么用的_电脑硬盘位不够用?有了它就不担心、奥睿科硬盘柜体验...
  3. 在tomcat上部署项目,实现类似添加这样的功能之后,tomcat要运行很久,解决办法
  4. 笔记-项目干系人管理
  5. 对DataTable里数据进行排序
  6. 《我和他的结婚录像和相册集》的快速传播
  7. php 怎么查看原生方法源码_你的2020搜索账单地址入口 你的2020搜索账单怎么查看查看方法...
  8. 课程《设计模式之美》笔记之关于面向对象与面向过程
  9. 2018年香港访港旅客超6500万人次 创16年新高
  10. mysql 虚拟表 分页_MySql大表分页(附独门秘技)
  11. Python全栈开发——线程与进程的概念
  12. Cocos2d 利用继承Draw方法制作可显示三维数据(宠物三维等)的三角形显示面板...
  13. 关于ORA-00257问题的解决(归档程序错误)
  14. 谷歌离线地图WMS/WMTS服务
  15. android模拟器安装frida
  16. POJ-1436___Horizontally Visible Segments —— 线段树
  17. python基础学习笔记
  18. 开学季将至 华硕重炮手主板让你学习娱乐两不误
  19. Android adb: failed to install 0.apk: Failure [null]
  20. android打印功能,Android通过OTG线连接打印机实现打印功能

热门文章

  1. HDU 2457 DNA repair(AC自动机 + DP)题解
  2. es6箭头函数内部判断
  3. UnderWater+SDN论文之六
  4. Jmeter-配置元件
  5. 来教你用什么泡脚好,泡脚的好处有那些?
  6. jQuery Callback 方法
  7. int 占一个机器字长
  8. GDI+中发生一般性错误 Winform Image.Save(mstream, ImageFormat.Png)引发
  9. 8月| R社区原创作者免费赠书
  10. R语言绘制流程图(一)