注:点击题目可直接跳转至leetcode相应的题目代码提交处
03. 数组中重复的数字
题目
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
思路
首先看限制n的范围,发现10万并不算大,所以可以使用哈希,利用下标来计算每个数出现的次数,因为是随意输出一个重复的数字,可以在统计时就看是不是重复了,如果重复了就输出;
代码
int a[100001];
int findRepeatNumber(vector<int>& nums) {
int n=nums.size();
for(int i=0;i<n;i++)
{
int tmp=nums[i];
a[tmp]+=1;
if(a[tmp]>1)
{
return tmp;
}
}
return 0;
}
04. 二维数组中的查找
题目
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
思路
经过评论区提示,可以从右上角看这个矩阵,这样就变成了一个二叉搜索树,然后依次判断即可,注意不要超出矩阵范围。点matrix[i][j]
的两个子节点是matrix[i][j-1]
和matrix[i+1][j]
代码
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
if(matrix.size()==0||matrix[0].size()==0)
{
return false;
}
int line=matrix.size();
int cor=matrix[0].size();
int i=0;
int j=cor-1;
while(i<line&&j>=0)
{
if(matrix[i][j]==target)
{
return true;
}
else if(target<matrix[i][j])
{
j--;
}
else
{
i++;
}
}
return false;
}
注意刚开始一定要检查空矩阵的情况,且一定要放在最前面检查,否则力扣会报错:Char 9: runtime error: reference binding to null pointer of type 'std::vector<int, std::allocator<int>>' (stl_vector.h)
05. 替换空格
题目
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."
限制:
0 <= s 的长度 <= 10000
思路
调用C++中固有的关于string类型的函数,详情见:https://www.cnblogs.com/wwj321/p/12381569.html
代码
string replaceSpace(string s) {
int n=s.size();
string s1="\%20";
for(int i=0;i<n;i++)
{
if(s[i]==' ')
{
s.erase(i,1);
s.insert(i,s1);
n=n+2;
i=i+2;
}
}
return s;
}
06. 从尾到头打印链表
题目
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
思路
从反过来可以直接想到用栈。
代码
vector<int> reversePrint(ListNode* head) {
stack<int> S;
ListNode *h=head;
while(h!=NULL)
{
S.push(h->val);
h=h->next;
}
int num=S.size();
vector<int> vec(num);
for(int i=0;i<num;i++)
{
vec[i]=S.top();
S.pop();
}
return vec;
}
07. 重建二叉树
题目
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7
思路
例如有树:
A
/
B C
前序遍历,为ABC,中序遍历为:BAC;可现根据前序遍历找到根节点,然后根据中序遍历分成左右树,再递归左右子树进行建树;
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size()==0)
{
return NULL;
}
TreeNode* root;
root =new TreeNode;
root->left=NULL;
root->val=preorder[0];
root->right=NULL;
int num=preorder.size(); //inorder的size也一样
vector<int> inleft;
vector<int> preleft;
vector<int> preright;
vector<int> inright;
for(int i=0;i<num;i++)
{
if(i!=0)
{
preleft.push_back(preorder[i]);
}
inleft.push_back(inorder[i]);
if(inorder[i]==preorder[0])
{
for(int j=i+1;j<num;j++)
{
preright.push_back(preorder[j]);
inright.push_back(inorder[j]);
}
root->left=buildTree(preleft,inleft);
root->right=buildTree(preright,inright);
return root;
}
}
return root;
}
};
我这个是将左右的代码都重新分配到新的数组了。也可以一直用原 有的两个数组,重新写一个递归的函数,将数组下标加入到参数中,这样不用讲原数组移动到新的数组。
关于treeNode
定义,可以这样写:
TreeNode* root=new TreeNode(preorder[0]);
09. 用两个栈实现队列
题目
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
示例 1:
输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]
思路
队列:先进先出;栈:先进后出
将数据存储在一个栈中,当增加数据时,直接加在栈后面;当删除数据时,将所有数据弹入到另一个栈暂存,然后将栈底的数据删掉,再将暂存的数据弹回来。(有点像汉诺塔)
代码
class CQueue {
public:
stack<int> S1;
stack<int> S2;
CQueue() {
}
void appendTail(int value) {
S1.push(value);
}
int deleteHead() {
if(S1.empty())
{
return -1;
}
while(!S1.empty())
{
int a=S1.top();
S1.pop();
S2.push(a);
}
int k=S2.top();
S2.pop();
while(!S2.empty())
{
int b=S2.top();
S2.pop();
S1.push(b);
}
return k;
}
};
10- I. 斐波那契数列
题目
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
思路
递归会比较耗时好空间,斐波那契数列可以直接循环计算,不用递归。
代码
class Solution {
public:
int fib(int n) {
if(n==0)
{
return 0;
}
if(n==1)
{
return 1;
}
int tmp;
int a,b;
a=0;
b=1;
for(int i=2;i<=n;i++)
{
tmp=a+b;
if(tmp>1000000007)
{
tmp=tmp-1000000007; //注:这里原本是取余数运算,因为是一次次加的,
//所以可以改成减法,减法计算速度快很多,
//可以击败100%,如果是取余慢很多
}
a=b;
b=tmp;
}
return tmp;
}
};
10- II. 青蛙跳台阶问题
题目
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
思路
最简单的动态规划类题目,可以看作是斐波那契数列;
代码
class Solution {
public:
int numWays(int n) {
if(n==0)
{
return 1;
}
if(n==1)
return 1;
if(n==2)
return 2;
int a,b;
a=1;
b=2;
int tmp;
for(int i=3;i<=n;i++)
{
tmp=a+b;
if(tmp>1000000007)
{
tmp=tmp-1000000007;
}
a=b;
b=tmp;
}
return tmp;
}
};