149. 直线上最多的点数
给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。
示例 1:
输入:points = [[1,1],[2,2],[3,3]]
输出:3
示例 2:
输入:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出:4
提示:
1
<
=
p
o
i
n
t
s
.
l
e
n
g
t
h
<
=
300
1 <= points.length <= 300
1<=points.length<=300
p
o
i
n
t
s
[
i
]
.
l
e
n
g
t
h
=
=
2
points[i].length == 2
points[i].length==2
−
1
0
4
<
=
x
i
,
y
i
<
=
1
0
4
-10^4 <= x_i, y_i <= 10^4
−104<=xi,yi<=104
points 中的所有点 互不相同
主要思路就是二重循环进行枚举,枚举从一个点开始,到其它点上的斜率,如果一致,就保存在map里,同时记录他出现的次数。这里需要涉及到一个的hash过程,参考了题解:https://leetcode.cn/problems/max-points-on-a-line/solutions/842114/zhi-xian-shang-zui-duo-de-dian-shu-by-le-tq8f/
同时,需要利用 δ x \delta x δx 和 δ y \delta y δy来表示 k = δ x δ y k=\frac{\delta x}{\delta y} k=δyδx,防止出现精度误差。因此,需要进行一个最小公约数的化简。
#include <vector>
#include <unordered_map>
#include <cmath>
using namespace std;
class Solution
{
int gcd(int x, int y)
{
return y > 0 ? gcd(y, x % y) : x;
}
public:
int maxPoints(vector<vector<int>> &points)
{
int n = points.size();
if (n <= 2)
return n;
int res = 0;
for (int i = 0; i < n; i++)
{
if (res > n - i || res > n / 2)
{
break;
}
unordered_map<int, int> mp;
for (int j = i + 1; j < points.size(); j++)
{
int x = points[j][0] - points[i][0];
int y = points[j][1] - points[i][1];
if (x == 0)
{
y = 1;
}
else if (y == 0)
{
x = 1;
}
else
{
if (y < 0)
{
y = -y;
x = -x;
}
int gcdXY = gcd(abs(x), abs(y));
x /= gcdXY;
y /= gcdXY;
}
mp[y + x * 20001]++;
}
for (auto &[_, num] : mp)
{
res = max(res, num + 1);
}
}
return res;
}
};
162. 寻找峰值
峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 n u m s [ − 1 ] = n u m s [ n ] = − ∞ nums[-1] = nums[n] = -∞ nums[−1]=nums[n]=−∞ 。
你必须实现时间复杂度为 O(log n) 的算法来解决此问题。
示例 1:
输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。
示例 2:
输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5
解释:你的函数可以返回索引 1,其峰值元素为 2;
或者返回索引 5, 其峰值元素为 6。
提示:
1 <= nums.length <= 1000
−
2
31
<
=
n
u
m
s
[
i
]
<
=
2
31
−
1
-2^{31} <= nums[i] <= 2^{31} - 1
−231<=nums[i]<=231−1
对于所有有效的 i 都有 nums[i] != nums[i + 1]
主要思路就是二分查找,具体的是,沿着数组,往大的方向走。
#include <vector>
#include <iostream>
using namespace std;
class Solution
{
public:
int findPeakElement(vector<int> &nums)
{
int n = nums.size();
int left = 0;
int right = n - 1;
int mid = -1;
while (left <= right)
{
mid = (left + right) / 2;
if ((mid + 1 == n || nums[mid + 1] < nums[mid]) &&
(mid - 1 == -1 || nums[mid - 1] < nums[mid]))
{
break;
}
if (mid + 1 == n || nums[mid + 1] > nums[mid])
{
left = mid + 1;
}
else if (mid - 1 == -1 || nums[mid - 1] > nums[mid])
{
right = mid - 1;
}
}
return mid;
}
};
int main()
{
vector<int> vec = {1, 2, 3, 9, 5};
Solution sol;
int res = sol.findPeakElement(vec);
cout << res;
}
166. 分数到小数
给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以 字符串形式返回小数 。
如果小数部分为循环小数,则将循环的部分括在括号内。
如果存在多个答案,只需返回 任意一个 。
对于所有给定的输入,保证 答案字符串的长度小于 104 。
示例 1:
输入:numerator = 1, denominator = 2
输出:“0.5”
示例 2:
输入:numerator = 2, denominator = 1
输出:“2”
示例 3:
输入:numerator = 4, denominator = 333
输出:“0.(012)”
提示:
−
2
31
<
=
n
u
m
e
r
a
t
o
r
,
d
e
n
o
m
i
n
a
t
o
r
<
=
2
31
−
1
-2^{31} <= numerator, denominator <= 2^{31} - 1
−231<=numerator,denominator<=231−1
denominator != 0
这道题目的关键就是如何找到循环的部分,很巧妙:
计算小数部分时,每次将余数乘以 10,然后计算小数的下一位数字,并得到新的余数。重复上述操作直到余数变成 0 或者找到循环节。
如果余数变成 0,则结果是有限小数,将小数部分拼接到结果中。
如果找到循环节,则找到循环节的开始位置和结束位置并加上括号,然后将小数部分拼接到结果中。
如何判断是否找到循环节?注意到对于相同的余数,计算得到的小数的下一位数字一定是相同的,因此如果计算过程中发现某一位的余数在之前已经出现过,则为找到循环节。为了记录每个余数是否已经出现过,需要使用哈希表存储每个余数在小数部分第一次出现的下标。1
#include <string>
#include <map>
using namespace std;
class Solution
{
public:
string fractionToDecimal(int numerator, int denominator)
{
long long numeratorLong = numerator;
long long denominatorLong = denominator;
if (denominatorLong == 0)
{
return "";
}
string res = "";
// 获取符号部分
if ((double)numeratorLong / denominatorLong < 0)
{
res += "-";
numeratorLong = abs(numeratorLong);
denominatorLong = abs(denominatorLong);
}
// 计算整数部分
int intPart = numeratorLong / denominatorLong;
res += to_string(intPart);
// 小数部分
int remainder = numeratorLong % denominatorLong;
if (remainder == 0)
{
return res;
}
// 拼接小数点
res += ".";
// 计算小数部分
string fractionPart = "";
// 建立map来记录之前出现过的数字(数字-index)
map<int, int> mp;
int idx = 0;
while (remainder != 0)
{
// 计算当前位的小数
fractionPart += to_string(remainder * 10 / denominatorLong);
// 说明还没有存在重复的余数
if (mp.find(remainder) == mp.end())
{
mp[remainder] = idx;
}
else
{
// 获取循环小数部分
string repeatPart = fractionPart.substr(mp[remainder], idx - mp[remainder]);
// 拼接小数部分整体
fractionPart = fractionPart.substr(0, mp[remainder]) + "(" + repeatPart + ")";
break;
}
remainder = remainder * 10 % denominatorLong;
idx++;
}
res += fractionPart;
return res;
}
};
171. Excel 表列序号
给你一个字符串 columnTitle ,表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。
例如:
A -> 1
B -> 2
C -> 3
…
Z -> 26
AA -> 27
AB -> 28
…
示例 1:
输入: columnTitle = “A”
输出: 1
示例 2:
输入: columnTitle = “AB”
输出: 28
示例 3:
输入: columnTitle = “ZY”
输出: 701
提示:
1 <= columnTitle.length <= 7
columnTitle 仅由大写英文组成
columnTitle 在范围 [“A”, “FXSHRXW”] 内
就是字符串转化为int,相当于是26进制而已,代码如下:
#include <string>
using namespace std;
class Solution
{
public:
int titleToNumber(string columnTitle)
{
int res = 0;
for(int i=0;i<columnTitle.size();i++){
int tmp = columnTitle[i] - 'A' + 1;
res = res * 26 + tmp;
}
return res;
}
};
https://leetcode.cn/problems/fraction-to-recurring-decimal/solutions/1028368/fen-shu-dao-xiao-shu-by-leetcode-solutio-tqdw/ ↩︎