目录
- T1 二维部分有序数组查找 ☆
- T2 字符串字符不等长替换 - 从后往前
- T3 返回链表的反序 vector
- T4 重建二叉树
- T5 两个栈模拟队列
- T6 旋转数组中的最小元素 - 二分或暴力 ☆
- T7 - 10 斐波那契数列 - 递推递归 - 两变量写法
- T11 二进制中 1 的个数
- T12 数值的整数次方 - 缜密 - 基数可能为负数
T1 二维部分有序数组查找 ☆
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
由于矩阵部分有序,向上数字递减,向右数字递增:
- 目标数字只会出现在行首小于该数的行中
- 遍历行i ,若列j 对应的元素大于目标,那么在前 i-1 行,目标只会出现在 j列及以后。
因此,可以从左下角开始查找。目标比左下角数字小时,上移;当要目标比左下角数字大时,右移。
搜索的路线是阶梯状,复杂度为O(行数+列数)。
class Solution {
public:
bool Find(int target, vector > array) {
int nrows = array.size();
int ncols = array[0].size();
int i = nrows - 1, j = 0;
while(i >= 0 && j < ncols){
if(array[i][j] == target) return true;
else if(array[i][j]< target ){
j++;
}else i--;
}
return false;
}
};
WA警告:
之前的错误代码版本如下,由于判断条件中的 && 写成 , 造成段错误(数组越界访问):
class Solution {
public:
bool Find(int target, vector > array) {
int nrows = array.size();
int ncols = array[0].size();
if( ncols == 0 || nrows == 0) return false;
for(int i = nrows - 1, j = 0; i >= 0, j < ncols; i--){
if( array[i][j] == target )
return true;
if( array[i][j] < target){
i++;
j++;
}
}
return false;
}
};
T2 字符串字符不等长替换 - 从后往前
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
实现统计好空格数目从后往前写。问题是 str 所指的空间会内存泄露吧?
注意补上 '\0'(应该不会有憨憨如我补了一个'\n'...
T3 返回链表的反序 vector
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
递归或者对正序 vector reverse。
class Solution {
public:
vector printListFromTailToHead(ListNode* head) {
vector rst;
if(head == NULL)return rst;
rst = printListFromTailToHead(head->next);
rst.emplace_back(head->val);
return rst;
}
};
//----------------------vv---------------------------------
class Solution {
public:
vector printListFromTailToHead(ListNode* head) {
vector rst;
ListNode* pNode = head;
while(pNode!=NULL){
rst.emplace_back(pNode->val);
pNode=pNode->next;
}
reverse(rst.begin(),rst.end());
return rst;
}
};
T4 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
递归建树。注意递归出口,当有 0 或一个节点时直接返回。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector pre,vector vin) {
if(pre.size()==0)
return NULL;
if(pre.size()==1)
return new TreeNode(pre[0]);
TreeNode* root = new TreeNode(pre[0]);
int lenl =0, lenr = 0,len = vin.size();
while(lenl npre,nvin;
npre = vector(pre.begin()+1,pre.begin()+1+lenl);
nvin = vector(vin.begin(),vin.begin()+lenl);
root->left = reConstructBinaryTree(npre,nvin);
npre = vector(pre.begin()+1+lenl,pre.end());
nvin = vector(vin.begin()+lenl+1,vin.end());
root->right = reConstructBinaryTree(npre,nvin);
return root;
}
};
T5 两个栈模拟队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
栈1接收入队列元素,栈2存储出队列元素,当栈2空时,把栈1元素倒到栈2中。
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
if(stack2.size()==0){
while(!stack1.empty()){
int x=stack1.top();
stack1.pop();
stack2.push(x);
}
}
int x=stack2.top();
stack2.pop();
return x;
}
private:
stack stack1;
stack stack2;
};
T6 旋转数组中的最小元素 - 二分或暴力 ☆
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
由于旋转后,数组前半段非减,后半段非减,所以从后往前遍历,转折点一定是最小元素。如果没有转折点,那么所有元素都相等。
. .··
. ·``
但是这个转折点可以试着二分。由于转折处的右侧是最小元素,所以选择尽量让区间右端点落在最小元素上。那么:
- array[mid] > array[high]
出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边。
low = mid + 1 - array[mid] == array[high]:
出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边还是右边,这时只好一步步缩小区间。
high = high - 1 - array[mid] < array[high]:
出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左边。因为右边必然都是递增的。
high = mid
注意,考虑最后区间长为2或为3 的情况,上述的收敛方式都会使得 low 和 high 最终都指向最小元素。
class Solution {
public:
int minNumberInRotateArray(vector rotateArray) {
if(rotateArray.size()==0)
return 0;
int lo =0, hi = rotateArray.size()-1,mid;
while(lo< hi){
mid = lo+((hi-lo)>>1);
if(rotateArray[mid]>rotateArray[hi])
lo=mid+1;
else if (rotateArray[mid] == rotateArray[hi])
hi-=1;
else hi=mid;
}
return rotateArray[hi];
}
};
T7 - 10 斐波那契数列 - 递推递归 - 两变量写法
T7:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。 n<=39。
class Solution {
public:
int Fibonacci(int n) {
if(n==0) return 0;
if(n==1) return 1;
if(n==2) return 1;
return Fibonacci(n-1)+Fibonacci(n-2);
}
};
T8:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
// 两变量
class Solution {
public:
int jumpFloor(int number) {
if(number==0)return 1;
if(number==1)return 1;
if(number==2)return 2;
int f=1,g=2;
number-=2;
while(number--){
g=f+g;
f=g-f;
}
return g;
}
};
T9:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
// dp
class Solution {
public:
int jumpFloorII(const int number) {
int** dp=new int*[number+10];
for(int i=0;i
T10:我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
类似于前面几题。
class Solution {
public:
int rectCover(int number) {
if(number==0) return 0;
if(number==1) return 1;
if(number==2) return 2;
int f=1,g=2;
number-=2;
while(number--){
g=f+g;
f=g-f;
}
return g;
}
};
T11 二进制中 1 的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
注意对于负数,右移一位会补 1 而非补零。
// 1. 去掉符号位 1
class Solution {
public:
int NumberOf1(int n) {
int cnt=0;
if(n<0) {
n &=0x7fffffff;
cnt++;
}
while(n){
cnt+=(n&1);
n>>=1;
}
return cnt;
}
};
// 2. 转为 unsigned int
class Solution {
public:
int NumberOf1(int n) {
unsigned int nn=n;
int cnt=0;
while(nn){
cnt+=(nn&1);
nn>>=1;
}
return cnt;
}
};
// 3. 每次 n&(n-1) 将从右边起的第一个 1 变为 0
public class Solution {
public int NumberOf1(int n) {
int count = 0;
while(n!= 0){
count++;
n = n & (n - 1);
}
return count;
}
}
T12 数值的整数次方 - 缜密 - 基数可能为负数
给定一个double类型的浮点数 base 和 int 类型的整数exponent。求base的exponent次方。 保证base和exponent不同时为0
class Solution {
public:
double Power(double base, int exponent) {
double ans=1;
bool neg= false;
else if(exponent<0){
neg=true;
exponent=-exponent;
}
for( ; exponent; base*=base,exponent/=2){
if(exponent&1){
ans*=base;
}
}
return neg?1/ans:ans;
}
};