LeetCode算法入门(第五十天)
二分查找
153.寻找旋转排序数组中的最小值
题目中的旋转更像是将数组看成首尾相连的,然后移动,故此数组总有一部分是有序的。
如果中间值大于右边的值,说明原先右边大的值已经旋转到了左边,此时应在右边区间找最小值;
同理。
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) { /* 中值 > 右值,最小值在右半边,收缩左边界 */
left = mid + 1; /* 因为中值 > 右值,中值肯定不是最小值,左边界可以跨过mid */
} else if (nums[mid] < nums[right]) { /* 明确中值 < 右值,最小值在左半边,收缩右边界 */
right = mid; /* 因为中值 < 右值,中值也可能是最小值,右边界只能取到mid处 */
}
}
return nums[left];
}
};
162.寻找峰值
因为峰值是严格大于它左右的元素,如果存在左右相邻的元素大于当前值,说明当前值不是峰值,转而判断那个大的元素的左右值。
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int n = nums.size();
if(n == 1) return 0;
// 先特判两边情况
if(nums[0] > nums[1]) return 0;
if(nums[n - 1] > nums[n - 2]) return n - 1;
int l = 0, r = n - 1;
while(l <= r) {
int mid = (l + r) / 2;
// 当前为峰值
if(mid >= 1 && mid < n - 1 && nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) {
return mid;
} else if(mid >= 1 && nums[mid] < nums[mid - 1]) {
// 峰值在 mid 左侧
r = mid - 1;
} else if(mid < n - 1 && nums[mid] < nums[mid + 1]) {
// 峰值在 mid 右侧
l = mid + 1;
}
}
return -1;
}
};
双指针
82.删除排序链表中的重复元素Ⅱ
正常的链表遍历,然后判断两个节点的值,但是当连续出现重复元素,需要在删除节点前需要记录
,然后不断的从链表中移除元素值相同的节点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head){
return head;
}
ListNode* dummy = new ListNode(0, head);
ListNode* pre = dummy; //哑结点,pre->next指向头节点
while(pre->next && pre->next->next){
if(pre->next->val == pre->next->next->val){
int x = pre->next->val; //当两个节点值相同时,删除前先记录节点值
while(pre->next && pre->next->val == x){
pre->next = pre->next->next; //更新节点
}
}
else{
pre = pre->next;
}
}
return dummy->next;
}
};
15.三数之和
因为数组中有重复元素,所以可能存在多组相同的解,因为需要额外判断跳过重复的解。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end()); //sort默认升序排列
for(int i = 0; i < nums.size(); i++){
if(nums[i] > 0) //若排序后第一个元素大于0,则不可能三树之和为0
return result;
if(i > 0 && nums[i] == nums[i-1]){ //跳过重复元素
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while(right >left){
if(nums[i] + nums[right] + nums[left] > 0){
right--;
}
else if(nums[i] + nums[right] + nums[left] < 0){
left++;
}
else{
result.push_back(vector<int>{nums[i] , nums[left] , nums[right]}); //返回的结果为一个三元组 这里要要强转一下
while(right > left && nums[right] == nums[right - 1]) //跳过重复元素
right--;
while(right > left && nums[left] == nums[left + 1]) //跳过重复元素
left++;
//找到一组后,左右指针都需收缩
right--;
left++;
}
}
}
return result;
}
};