1.数值的整数平方(分治,快速幂)
题目内容:
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,
x
n
x^n
xn)。不得使用库函数,同时不需要考虑大数问题。
难度:中等
数据范围:
- − 100.0 < x < 100.0 -100.0 < x < 100.0 −100.0<x<100.0
- − 2 31 ≤ n ≤ 2 31 -2^{31} \le n \le 2^{31} −231≤n≤231
- − 1 0 4 ≤ x n ≤ 1 0 4 -10^4\le x^n \le 10^4 −104≤xn≤104
https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/
题解:
首先,暴力求解是不可行的,时间复杂度为O(n)的for循环会超出时间限制。
考虑用分治算法,将时间复杂度提高至O(logn)。
方法一:
class Solution {
public:
double myPow(double x, int n) {
if(n==1)
return x;
else if(n==-1)
return 1.0/x;
else if(n==0)
return 1.0;
double half=myPow(x,n/2);
double mod=myPow(x,n%2);
return half*half*mod;
}
};
代码并不复杂,只有递归栈产生的内存消耗,时间复杂度也减少到了logn,并且巧妙的用mod解决了乘方为奇偶的情况。
方法二:快速幂
class Solution {
public:
double myPow(double x, int n) {
if(x == 0) return 0;
long b = n;
double res = 1.0;
if(b < 0) {
x = 1 / x;
b = -b;
}
while(b > 0){
// 最后一位为1,需要乘上该位上的权重
if((b & 1) == 1){
res *= x;
}
x *= x;
b >>= 1;
}
return res;
}
}
/*
作者:ollieq
链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/solution/jian-dan-li-jie-kuai-su-mi-by-ollieq-rl74/
来源:力扣(LeetCode)*/
快速幂:
例如要计算
x
11
x^{11}
x11,因为11的二进制为1011,
x
11
x^{11}
x11就可以转化为
x
2
3
+
2
1
+
2
0
=
x
2
3
∗
x
2
1
∗
x
2
0
x^{2^{3}+2^{1}+2^{0}}=x^{2^{3}}*x^{2^{1}}*x^{2^{0}}
x23+21+20=x23∗x21∗x20,从之前需要计算11次乘法,减少到只需要算三次(经历四次循环,因为1011有四位),时间复杂度为O(logn)。
代码中每经历一次循环,
x
x
x的值变为
x
∗
x
x*x
x∗x,即
x
,
x
2
,
x
4
,
x
8
.
.
.
x,x^{2},x^{4},x^{8}...
x,x2,x4,x8...。只有n的对应位置上的二进制数为1时,才会执行
r
e
s
∗
=
x
res*=x
res∗=x。
2.给定二叉树的后序遍历,判断该二叉树是否为二叉搜索树
题目内容:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
难度:中等
数据范围:
数组长度
≤
\le
≤ 1000
https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/
题解:
自己写的很麻烦,就不贴上来了,主要思想是后序遍历和中序遍历可以唯一确定一颗二叉树,再判断这颗二叉树是否为二叉搜索树。
下面给出优秀题解代码:
class Solution {
public:
bool verifyPostorder(vector<int>& postorder) {
return cheak(postorder,0,postorder.size()-1);
}
//后序 左->右->根
bool cheak(vector<int>& p,int l,int r){
if(l>=r)
return true;
int idx=l;
while(p[idx]<p[r])
idx++; //找到右树根节点
int f=idx;
while(p[f]>p[r]) //f==r 用于判断此树是否正确 即左子树结点都小于根节点 右子树结点都大于根节点
f++;
return f==r&&cheak(p,l,idx-1)&&cheak(p,idx,r-1);
}
};
/*
作者:zai-ye-bu-hui
链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/solution/fen-zhi-zuo-you-zi-shu-fen-bie-pan-duan-8bdzy/
来源:力扣(LeetCode)
*/
主要思想为,根据二叉搜索树的性质,结点的左子树上所有结点的值均小于该节点的值,右子树上所有结点的值均大于该结点(题目说明所有结点值均不同,不考虑相同的情况)。后续遍历的顺序为左->右->根。
从前往后遍历数组,直到某一个元素的值不小于根结点(数组最后一个元素的值),那么左子树遍历完成,再继续遍历,直到某一个元素的值不大于根节点,那么右子树遍历完成,因为不存在值相同的结点,那么此时的元素一定是根,否则该树就不是一个平衡二叉树(判断条件f==r)。
再依次方法判断左子树和右子树,是否均为平衡二叉树。
3.乘积小于K的子数组(双指针)
题目内容:
给定一个正整数数组 nums和整数 k 。请找出该数组内乘积小于 k 的连续的子数组的个数。
难度:中等
数据范围:
- 1 ≤ \le ≤ nums.length ≤ \le ≤ 3 * 104
- 1 ≤ \le ≤nums[i] $\le$1000
- 0 ≤ \le ≤ k ≤ \le ≤ 106
https://leetcode-cn.com/problems/subarray-product-less-than-k/
示例:
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。
题解:
class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
if(k<=1)
return 0;
int ans=0;
int n=nums.size();
int left=0;
int product=1;
for(int right=0;right<n;right++){
product*=nums[right];
while(product>=k){
product/=nums[left];
left++;
}
ans+=right-left+1;//为什么这样算
}
return ans;
}
};
双指针的思想不难理解,重点是理解ans+=right-left+1这句代码。
每次执行更新ans的操作时,都保证数组中[left-right]长度的乘积小于k,因为每次只统计以right为右边界的符合要求的数组的长度,而这个数组的长度就是[left-right]中符合乘积小于k的要求的子数组的数量。例如[5,2,6],右边界为6,符合要求的子数组为[6],[2,6],[5,2,6]。
4.两个列表的最小索引总和(哈希)
题目内容:
假设 Andy 和 Doris 想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示。
你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。 如果答案不止一个,则输出所有答案并且不考虑顺序。 你可以假设答案总是存在。
难度:简单
数据范围:
- 1 ≤ \le ≤ list1.length, list2.length ≤ \le ≤ 1000
- 1 ≤ \le ≤ list1[i].length, list2[i].length ≤ \le ≤ 30
- list1[i] 和 list2[i] 由空格 ’ ’ 和英文字母组成。
- list1 的所有字符串都是 唯一 的。
- list2 中的所有字符串都是 唯一 的。
https://leetcode-cn.com/problems/minimum-index-sum-of-two-lists/
题目示例:
输入: list1 = ["Shogun", "Tapioca Express", "Burger King", "KFC"],list2 = ["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
输出: ["Shogun"]
解释: 他们唯一共同喜爱的餐厅是“Shogun”。
题解:
class Solution {
public:
vector<string> findRestaurant(vector<string>& list1, vector<string>& list2) {
unordered_map<string, int> map;
vector<string> ans;
int pos=0x7fffffff;
for(int i=0;i<list2.size();i++)
map[list2[i]]=i;
for(int i=0;i<list1.size();i++){
if(map.count(list1[i])){
// cout<<1;
if(map[list1[i]]+i<pos){
ans.clear();
ans.push_back(list1[i]);
pos=map[list1[i]]+i;
}
else if(map[list1[i]]+i==pos)
{
ans.push_back(list1[i]);
}
}
}
return ans;
}
};