明年就是找工作了,又要开始刷题了,把之前做过的题目再梳理整理一遍,但愿明年不要那么拉跨,祈祷明年能找到工作,千万不能毕业就失业。
分类别解析leetcode上的一些相关的例题路,代码采用C++与python实现。
主要分为如下的三类题目: 对撞指针, 快慢指针, 其他双指针.
对撞指针的问题,一般是数组首尾各有一个指针,这俩指针往中间移动过,解决相对应的问题
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
class Solution {
public:
vector twoSum(vector& numbers, int target) {
// 首尾指针
int head = 0, tail = numbers.size() - 1;
while (head <= tail){
int point_sum = numbers[head] + numbers[tail];
if ( point_sum== target)
return {head + 1, tail + 1};
// 和小于target,首指针后移
else if (point_sum < target)
head++;
// 和大于target, 尾指针前移
else
tail--;
}
return {};
}
};
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。
class Solution {
public:
bool judgeSquareSum(int c) {
int head = 0;
int tail = static_cast(sqrt(c)) + 1;
while (head <= tail){
long point_sum = pow(head, 2) + pow(tail, 2);
if (point_sum == c)
return true;
else if (point_sum < c)
head++;
else
tail--;
}
return false;
}
};
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
class Solution {
public:
string reverseVowels(string s) {
// 首尾指针
int head = 0, tail = s.size() - 1;
// 利用无序的关联容器,存储原因字母表.
unordered_set vowels({'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'});
while(head < tail){
// 首指针找到元音字母
if(vowels.find(s[head]) == vowels.end())
head++;
//尾指针找到元音字母
else if(vowels.find(s[tail]) == vowels.end())
tail--;
else{
// 交换首尾指针对应的元音字母
swap(s[head], s[tail]);
// 移动首尾指针的值
head++;
tail--;
}
}
return s;
}
};
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
class Solution {
public:
bool isPalindrome(string s) {
int head = 0, tail = s.size() -1;
while (head < tail){
// isalnum() 数字或者字母时为真.
if (isalnum(s[head]) && isalnum(s[tail])){
// 忽略大小写,直接将其都转化为小写进行比较
if (tolower(s[head]) != tolower(s[tail]))
return false;
else
head++; tail--;
}
else if (! isalnum(s[head]))
head++;
else if (! isalnum(s[tail]))
tail--;
}
return true;
}
};
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串
class Solution {
public:
bool palindrome(string& s){
// 验证一个字符串是否为回文串
int head = 0, tail = s.size() - 1;
while (head < tail){
if (s[head] != s[tail])
return false;
else
head++; tail--;
}
return true;
}
bool validPalindrome(string s) {
int head = 0, tail = s.size() - 1;
while (head < tail){
if (s[head] == s[tail]) {
head++; tail--;
continue;
}
else{
string str1(s, head + 1, tail- head);
string str2(s, head, tail - head);
return palindrome(str1) || palindrome(str2);
}
}
return true;
}
};
class Solution {
public:
void reverseString(vector& s) {
int head = 0, tail = s.size() -1;
while (head < tail){
swap(s[head], s[tail]);
head++;
tail--;
}
}
};
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素
class Solution {
public:
int removeElement(vector& nums, int val) {
int head = 0, tail = nums.size() - 1;
while (head <= tail){
while (head <= tail && nums[tail] == val)
tail--;
if (nums[head] == val && head <= tail){
swap(nums[head], nums[tail]);
tail--;
}
head++;
}
return tail + 1;
}
};
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
长x高
, 长为两个指针之间的距离, 高由两个指针所对应的元素中的最小值决定.class Solution {
public:
int maxArea(vector& height) {
// 定义头尾指针
int head = 0, tail = height.size() - 1;
// 保存最大的矩形面积
long maxarea = 0;
while (head < tail){
// 左边低, 那么左指针右移找寻更高的 高
// 如果右指针左移, 那么高还是左指针的值,但是长变小了,只能移动短边
if (height[head] < height[tail]){
long area = height[head] * (tail - head);
maxarea = max(maxarea, area);
head++;
}
// 右边低,右指针左移
else {
long area = height[tail] * (tail - head);
maxarea = max(maxarea, area);
tail--;
}
}
return maxarea;
}
};
快慢指针是指两个指针从头开始一个快一个慢指针, 一般就是, 最经典的题目就是针对链表的问题(快慢指针查找链表的中心点).
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
class Solution {
public:
bool hasCycle(ListNode *head) {
if (head == nullptr || head->next == nullptr) return false;
// 定义快慢指针
ListNode* slow = head;
ListNode* fast = head->next;
// 如果fast指针没有到达链表的结尾,就持续移动快慢指针.
while (fast != nullptr && fast->next != nullptr){
// 如果二者相遇,说明有环
if (fast == slow) return true;
slow = slow->next;
fast = fast->next->next;
}
// 快指针到达链表的结尾,说明没有环.
return false;
}
};
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
class Solution {
public:
void moveZeroes(vector& nums) {
// 快慢指针
int slow=0, fast=0;
while (fast< nums.size()){
if (nums[fast] != 0){
swap(nums[fast], nums[slow]);
slow++;
}
fast++;
}
}
};
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
class Solution {
public:
int removeDuplicates(vector& nums) {
// 快慢指针
int slow = 0, fast = 0;
if (nums.size() == 0) return 0;
while (fast < nums.size()){
if (nums[fast] != nums[slow]){
slow++;
swap(nums[fast], nums[slow]);
}
fast++;
}
return slow+1;
}
};
给定一个增序排列数组 nums ,你需要在 原地 删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
这道题与上一题相比难在重复的字符可以出现两次.
class Solution {
public:
int removeDuplicates(vector& nums) {
if (nums.empty()) return 0;
if (nums.size() == 1) return 1;
int slow = 0, fast = 1;
int cnt = 1; //cnt表示某个字符出现的次数
while (fast < nums.size() ) {
if (nums[fast] == nums[slow]) {
// 如果这个字符仅仅出现了一次, 那么慢指针后移并赋值
if (cnt == 1) {
slow++;
nums[slow] = nums[fast];
cnt++;
}
//如果已经出现了两次,就直接快指针后移
}
// 如果不相等,那么直接复制,也就是字符仅仅出现一次
else {
slow++;
nums[slow] = nums[fast];
cnt = 1;
}
fast++;
}
return slow + 1;
}
};
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明:初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
方法3的代码如下: (也可以采用前两种方法试试,简单题应该也会通过)
class Solution {
public:
void merge(vector& nums1, int m, vector& nums2, int n) {
int i = m-1, j = n-1, k = 0;
while (i >= 0 && j >= 0){
if (nums1[i] > nums2[j]){
nums1[m + n - k - 1] = nums1[i];
i--;
}
else{
nums1[m + n - k - 1] = nums2[j];
j--;
}
k++;
}
if (j >= 0){
for (int s = 0; s <= j; s++){
nums1[s] = nums2[s];
}
}
}
};
给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。
class Solution {
public:
string findLongestWord(string s, vector& d) {
if (s.empty()) return "";
vector Words; // 存储所有满足条件的字串
for (auto e : d){
int p1 = 0, p2 = 0;
while (p1 < e.size() && p2 < s.size()){
if (e[p1] == s[p2])
{p1++;p2++;}
else
p2++;
}
if (p1 == e.size())
Words.push_back(e);
}
vector longestWord; // 保存满足条件的子串中最长的字串
int maxSize = 0;
for (auto e : Words){
if (e.size() == maxSize)
longestWord.push_back(e);
else if (e.size() > maxSize){
longestWord.clear();
longestWord.push_back(e);
maxSize = e.size();
}
}
sort(longestWord.begin(), longestWord.end());
if (longestWord.empty()) return "";
else return longestWord[0];
}
};