day2 牛客TOP100:BM 11-20 链表 二分法 流输入 小美加法

文章目录

  • 链表
    • BM11 链表相加(二)
    • BM12 单链表的排序
      • 归并排序+分割 超时
      • 辅助数组
      • 快排
    • BM13 判断一个链表是否为回文结构
    • BM14 链表的奇偶重排
    • BM15 删除有序链表中重复的元素-I
    • BM16 删除有序链表中重复的元素-II
    • JZ35 复杂链表的复制
  • 二分法
    • BM17 二分查找-I
    • BM18 二维数组中的查找
    • BM19 寻找峰值
    • BM20 数组中的逆序对
  • 流输入
    • 小美加法

链表

BM11 链表相加(二)

之前写过一个题目就是两个逆序链表相加,这个题是正序链表求和,思路就是先把链表反转,变成逆序链表,然后求和,再把链表反转回来。在这里插入图片描述

/*** struct ListNode {*	int val;*	struct ListNode *next;*	ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {
public:ListNode* addInList(ListNode* head1, ListNode* head2) {int flag = 0, val = 0;ListNode* dummyhead = new ListNode(-1);ListNode* temp = dummyhead;int val1 = 0, val2 = 0, sum = 0;head1 = reverselist(head1);head2 = reverselist(head2);//printlist(head1);//printlist(head2);while(head1 || head2){if(head1) val1 = head1->val;else val1 = 0;if(head2) val2 = head2->val;else val2 = 0;sum = val1 + val2 + flag;flag = sum / 10;sum = sum % 10;cout << "sum:" << sum << "  flag:" << flag << endl;temp->next = new ListNode(sum);temp = temp->next;if(head1) head1 = head1->next;if(head2) head2 = head2->next;}if(flag) temp->next = new ListNode(flag);dummyhead->next = reverselist(dummyhead->next);return dummyhead->next;}ListNode* reverselist(ListNode* node){if(node == nullptr) return node;ListNode* temp;ListNode* cur = node;ListNode* pre = nullptr;while(cur){temp = cur->next;cur->next = pre;pre = cur;cur = temp;}return pre;}void printlist(ListNode* head){while(head){cout << head->val << endl;head = head->next;}}
};

BM12 单链表的排序

在这里插入图片描述

归并排序+分割 超时

因为递归O(n) 会超时,无语了

/*** struct ListNode {*  int val;*  struct ListNode *next;*  ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {public:ListNode* sortInList(ListNode* head) {if (head == nullptr || head->next == nullptr) return head;// 分割 归并排序 超时        return cutlistTomerge(head);       }ListNode* cutlistTomerge(ListNode* head){if(head->next == nullptr) return head;// 使用快慢指针寻找链表的中点ListNode* fast = head;ListNode* slow = head;while (fast && fast->next) {fast = fast->next->next;slow = slow->next;}//断开链表ListNode* temp = slow->next;slow->next = nullptr;// 递归左右两边进行排序ListNode* left = cutlistTomerge(head);ListNode* right = cutlistTomerge(temp); return mergelist(left, right);}ListNode* mergelist(ListNode* head1, ListNode* head2){if(head1 == nullptr) return head2;if(head2 == nullptr) return head1;ListNode* dummyhead = new ListNode(0);ListNode* cur = dummyhead;while(head1 && head2){if(head1->val < head2->val){cur->next = head1;head1 = head1->next;}else {cur->next = head2;head2 = head2->next;}cur = cur->next;}cur->next = (head1 == nullptr) ? head2 : head1;return dummyhead->next;}
};

辅助数组

用一个辅助数组保存结点值,然后排序,然后从表头逐渐更改结点值,排序用的内置函数sort。

/*** struct ListNode {*  int val;*  struct ListNode *next;*  ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {public:ListNode* sortInList(ListNode* head) {if (head == nullptr || head->next == nullptr) return head;//数组保存 二分法vector<int> nums;ListNode* dummyhead = head;while(dummyhead){nums.push_back(dummyhead->val);dummyhead = dummyhead->next;}sort(nums.begin(), nums.end());dummyhead = head;for(int i=0; i<nums.size(); i++){dummyhead->val = nums[i];dummyhead = dummyhead->next;}return head;}void sortbinary(vector<int>& nums){int left = 0, right = nums.size();//左闭右开int mid;while(left < right){mid = left + (left + right) / 2;if(nums[left] > nums[mid]) }}
};

快排

有一个将排序的博客,挺详细的,谢谢五斤w的分享,吃透排序

用了一个快排

/*** struct ListNode {*  int val;*  struct ListNode *next;*  ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {public:ListNode* sortInList(ListNode* head) {if (head == nullptr || head->next == nullptr) return head;//数组保存 二分法vector<int> nums;ListNode* dummyhead = head;while(dummyhead){nums.push_back(dummyhead->val);dummyhead = dummyhead->next;}quickSort(nums, 0, nums.size()-1);dummyhead = head;for(int i=0; i<nums.size(); i++){dummyhead->val = nums[i];dummyhead = dummyhead->next;}return head;}int divide_quicksort(vector<int>& nums, int left, int right){int pivot = nums[left];while(left < right){while(left < right && nums[right] >= pivot) right--;//找到比基准值小的数了nums[left] = nums[right];//放在左边while(left < right && nums[left] <= pivot) left++;//找到比基准值大的数了nums[right] = nums[left];}nums[left] = pivot;//left和right指针重合,写right也可以return left;}void quickSort(vector<int>& nums, int left, int right){if(left < right){int pivot = divide_quicksort(nums, left, right);quickSort(nums, left, pivot-1);quickSort(nums, pivot+1, right);}}
};

BM13 判断一个链表是否为回文结构

在这里插入图片描述

一开始想反转前半部分的,老有问题,就改成了反转后半部分了。

/*** struct ListNode {*	int val;*	struct ListNode *next;*	ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {
public:bool isPail(ListNode* head) {ListNode* fast = head;ListNode* slow = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}//cout << "fast:" << fast->val << "  slow" << slow->val << "  slow-next" << slow->next->val << endl;//后半部分反转 slow是中点ListNode* reversehead = reverselist(slow);  while(reversehead){//cout << "head:" << head->val << "  reversehead" << reversehead->val<<endl;if(head->val == reversehead->val){head = head->next;reversehead = reversehead->next;}else return false;}return true;}ListNode* reverselist(ListNode* head){ListNode* pre = nullptr;ListNode* cur = head;ListNode* temp;while(cur){temp = cur->next;cur->next = pre;pre = cur;cur = temp;}return pre;}
};

BM14 链表的奇偶重排

在这里插入图片描述
看思路的写的,一个奇数位置开始,一个偶数位置开始,奇数结点指向 偶数结点的下一个。奇数指针更新;偶数结点指向 奇数结点的下一个。偶数指针更新。

/*** struct ListNode {*	int val;*	struct ListNode *next;*	ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {
public:ListNode* oddEvenList(ListNode* head) {if(head == nullptr) return head;ListNode* odd = head;ListNode* even = head->next;ListNode* evenhead = even;while(even && even->next){//奇数结点指向 偶数结点的下一个odd->next = even->next;odd = odd->next;//更新//偶数结点指向 奇数结点的下一个even->next = odd->next;even = even->next;//更新}odd->next = evenhead;return head;}ListNode* halflist(ListNode* node){ListNode* newhead = node;ListNode* cur = newhead;while(cur && cur->next){cur->next = cur->next->next;cur = cur->next;}return newhead;}
};

BM15 删除有序链表中重复的元素-I

在这里插入图片描述
一个结点遍历链表,如果当前结点与下一个结点值相等,逻辑删除,当前节点连接下下个节点,否则正常遍历。要注意只有一个结点的链表和空链表。

/*** struct ListNode {*	int val;*	struct ListNode *next;*	ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {if(head == nullptr || head->next == nullptr) return head;ListNode* pre = head;while(pre && pre->next){//如果相同 就逻辑删除 连接下一个if(pre->val == pre->next->val) pre->next = pre->next->next;else pre = pre->next;//否则正常更新}return head;}
};

BM16 删除有序链表中重复的元素-II

在这里插入图片描述

/*** struct ListNode {*	int val;*	struct ListNode *next;*	ListNode(int x) : val(x), next(nullptr) {}* };*/
class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {if(!head || !head->next) return head;ListNode* res = new ListNode(0);res->next = head;ListNode* cur = res;while(cur->next && cur->next->next){//cout << "cur:" << cur->val << "  cur.next" << cur->next->val;if(cur->next->val == cur->next->next->val){int temp = cur->next->val;while(cur->next != nullptr && cur->next->val == temp){cur->next = cur->next->next;}}else cur = cur->next;//cout << endl;            }return res->next;}
};

JZ35 复杂链表的复制

在这里插入图片描述

第二次写了,还是不会,又回去看了下第一次写的思路。
思路:用哈希表保存结点值及其指向。首先,复制新结点,此时哈希表只有单个新的结点,然后遍历哈希表内的结点,复制对应原结点的指向。

/*
struct RandomListNode {int label;struct RandomListNode *next, *random;RandomListNode(int x) :label(x), next(NULL), random(NULL) {}
};
*/
class Solution {
public:RandomListNode* Clone(RandomListNode* pHead) {if(pHead == nullptr) return nullptr;unordered_map<RandomListNode*, RandomListNode*> hashmap;//复制单个新的节点for(RandomListNode* cur = pHead; cur != nullptr; cur = cur->next){hashmap[cur] = new RandomListNode(cur->label);}//复制指向for(RandomListNode* cur = pHead; cur != nullptr; cur = cur->next){//新结点的next指向 hashmap[cur]->next = hashmap[cur->next];hashmap[cur]->random = hashmap[cur->random];}return hashmap[pHead];}
};

二分法

BM17 二分查找-I

在这里插入图片描述
简单的二分查找,如果目标值在中间值的左边,left=mid+1;否则right=mid-1

class Solution {
public:int search(vector<int>& nums, int target) {if(nums.size() == 0) return -1;int left = 0, right = nums.size()-1, mid = 0;while(left <= right){mid = left + (right - left) / 2;if(nums[mid] == target) return mid;if(target > nums[mid]) left = mid + 1;//在mid的右边else right = mid-1;//在mid的左边}return -1;}
};

BM18 二维数组中的查找

在这里插入图片描述
这是一个行列都递增的数组,有两种做法,一是从右上角往左下角逼近,二是每一行都二分查找。

  • 每一行二分查找
class Solution {
public:bool Find(int target, vector<vector<int> >& array) {if(array.size() == 0) return false;//每一行二分查找for(int i=0; i<array.size(); i++)if(binaryserach(array[i], target)) return true;return false;}bool binaryserach(vector<int>& array, int target){int left = 0, right = array.size()-1, mid = 0;while(left <= right)//注意取等号 否则无法取区间两边的值{mid = left + (right - left) / 2;if(target == array[mid]) return true;if(target < array[mid]) right = mid - 1;//target在左边 缩小右边界else left = mid + 1;}return false;}
};
  • 右上角往左下角逼近
class Solution {
public:bool Find(int target, vector<vector<int> >& array) {if(array.size() == 0) return false;//右上角往左下角逼近int row = 0, col = array[0].size()-1;while (row < array.size() && col >= 0) {//printf("%d %d %d\n", row, col, array[row][col]);if(target == array[row][col]) return true;if(target < array[row][col]) col--;//列数往回走else row++;//行数往下走}return false;}
};

BM19 寻找峰值

在这里插入图片描述
思路是记录左边的值,逐个比较,如果当前值比左右两边值大,或者当前值比左边大且到数组末尾,都认为当前值是峰值。

class Solution {
public:int findPeakElement(vector<int>& nums) {if(nums.size() < 2) return 0;int left = nums[0];for(int i=1; i<nums.size(); i++){if(nums[i] > left && (nums[i] > nums[i+1] || i==nums.size()-1)) return i;else left = nums[i];}return 0;}
};

二分查找

class Solution {
public:int findPeakElement(vector<int>& nums) {if(nums.size() < 2) return 0;int left = 0, right = nums.size()-1, mid = 0;while (left < right) {mid = left + (right - left) / 2;//右边是往下,不一定有坡峰if(nums[mid] > nums[mid+1]) right = mid;else left = mid+1;}return right;}
};

BM20 数组中的逆序对

在这里插入图片描述
思路:两层for循环暴力,外循环固定当前值,内循环从当前值的后一个开始遍历,找到一个小的数字就计数,当前值统计完了,内循环结束,外循环开始下一轮。
其实,暴力法在找到最小值的时候重复了很多遍。比如,内循环找到一个小的值,如果此时外循环继续后移的话,就省去了很多麻烦。

class Solution {
public:using ll = long long;ll mod = 1000000007;int InversePairs(vector<int>& nums) {if(nums.size() <= 1) return 0;ll res = 0;for(int i=0; i<nums.size(); i++)res += getreversenum(nums, i);return res%mod;}ll getreversenum(vector<int>& nums, int index){ll count = 0;for(int i=index+1; i<nums.size(); i++){//printf("%d %d %lld", nums[i], nums[index], count);if(nums[i] < nums[index]) count++;}return count % mod;}
};

并归排序做法 不是很会

class Solution {
private:using ll = long long;const int mod = 1000000007;
public:int InversePairs(vector<int>& nums) {if(nums.size() <= 1) return 0;ll res = 0;//并归排序vector<int> temp(nums.size());mergesort(nums, temp, 0, nums.size()-1, res);return res;}// 递归划分void mergesort(vector<int>& nums, vector<int>& temp, int left, int right, ll& res){// 只有一个数字,则停止划分if(left >= right)return;int mid = left + ((right - left) >> 1);//int mid = left + (right - left) / 2;mergesort(nums, temp, left, mid, res);mergesort(nums, temp, mid+1, right, res);// 合并两个有序区间merge_sorted(nums, temp, left, mid, right, res);}//合并void merge_sorted(vector<int>& nums, vector<int>& temp, int left, int mid, int right, ll& res){int i = left, j = mid + 1, k = 0;while(i <= mid && j<= right){if(nums[i] > nums[j]){temp[k++] = nums[j++];res += (mid - i + 1);//统计逆序数的个数 只统计逆序对里边数字较大的个数res %= mod;}else temp[k++] = nums[i++];}while(i <= mid)temp[k++] = nums[i++];while(j <= right)temp[k++] = nums[j++];for(k = 0, i = left; i<=right; ++i, ++k){nums[i] = temp[k];}}
};

流输入

写题的时候碰到输入要作为字符串进行分割的,因为不会就真的很烦,碰到这个题,学习一下。

istringstream是C++的输入输出控制类。C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含这个头文件。

①istringstream类用于执行C++风格的串流的输入操作。
②ostringstream类用于执行C风格的串流的输出操作。
③strstream类同时可以支持C风格的串流的输入输出操作。
istringstream的构造函数原形如下:istringstream::istringstream(string str);,作用是从string对象str中读取字符。

  • 用法1,读取每个字符,空格结束,如下:
#include<iostream>  
#include<sstream>        //istringstream 必须包含这个头文件
#include<string>  
using namespace std;  
int main()  
{  string str="this is istringstream";  //istringstream读取str中的每一个字符istringstream iss(str);  string temp;  while(iss >> temp)  cout << temp << endl; return 0;
} 

输出就是逐行打印temp字符串

this
is
istringstream
  • 用法2,结合getline()函数分割字符,如BM22题
#include<iostream>  
#include<sstream>        //istringstream 必须包含这个头文件
#include<string>  
using namespace std;  
int main()  
{  string str="this is istringstream";  vector<string> num1;istringstream ss1(version1);string temp;//按照 . 分割流输入while(getline(ss1, temp, '.'))num1.push_back(temp);
} 

num1数组里边存放的依次是this、is、istringstream字符串。

小美加法

第一次写的时候理解错题意了,以为找到最大的两个数字的乘积就好了。但其实是,要找的乘积要满足:两个数相邻,且这个乘积使得整体和最大。

  1. 所以先求原来的和,如果不使用魔法就返回原来的和;
  2. 然后两两一组取乘积,再用原来的和sum - num1 - num2 + num1 * num2,把这个结果保存起来,我存在了数组里边,也可以仅维护每一次的最大值就好。
  3. 最后取数组的最大值和原来的和比较,输出两者较大者即可。如果第二步维护最大值,这一步就不用取数组最大值了,直接比较就好了。
    在这里插入图片描述
#include <vector>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;using ll = long long;vector<ll> getsum(vector<ll>& v, ll sum)
{vector<ll> result(v.size(), 0);ll res = 0;int index = 0;for(int i=0; i<v.size(); i++){res = sum - v[i] - v[i+1] + v[i] * v[i+1];result[index++] = res;//printf("%lld %lld %lld %lld %lld %d\n", sum, v[i], v[i+1], v[i]*v[i+1], res, index);}return result;
}int main() {ll n, a;cin >> n;vector<ll> v;ll sum = 0;//初始和for(ll i=0; i<n; i++){cin >> a;sum += a;v.push_back(a);}//printf("%lld\n", sum);/*for(int i=0; i<v.size(); i++)printf("%d ", v[i]);*/vector<ll> result = getsum(v, sum);ll res = sum;for(auto r : result)res = max(res, r);printf("%lld", res);return 0;
}
// 64 位输出请用 printf("%lld")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/87675.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git中smart Checkout与force checkout

Git中smart Checkout与force checkout 使用git进行代码版本管理,当我们切换分支有时会遇到这样的问题&#xff1a; 这是因为在当前分支修改了代码&#xff0c;但是没有commit,所以在切换到其他分支的时候会弹出这个窗口&#xff0c; 提示你选force checkout或者smart checko…

Windows11 安装 nvm node版本管理工具

在 Windows 11 上安装并配置 NVM 与 Node.js 版本管理工具 引言&#xff1a; Node.js 是一款强大的开发工具&#xff0c;而版本管理工具 NVM 则可以帮助我们在不同的项目中灵活地切换和管理 Node.js 版本。本篇博客将为大家介绍如何在 Windows 11 操作系统上安装 NVM&#xff…

手机无人直播软件有哪些,又有哪些优势?

如今&#xff0c;随着智能手机的普及和移动互联网的发展&#xff0c;手机无人直播成为了一个炙手可热的领域。手机无人直播软件为用户提供了便捷、灵活的直播方式&#xff0c;让更多商家人能够实现自己的直播带货的梦想。接下来&#xff0c;我们将探讨手机无人直播软件有哪些&a…

【随笔】如何使用阿里云的OSS保存基础的服务器环境

使用阿里云OSS创建一个存储仓库&#xff1a;bucket 在Linux上下载并安装阿里云的ossutil工具 // 命令行&#xff0c;是linux环境 3. 安装ossutil。sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash 说明:安装过程中&#xff0c;需要使用解压工具…

AP9234 9W升压恒流型 DCDC多串LED恒流驱动 2串3串 LED灯串

描述 AP9234是一款由基准电压源、振荡电路、误差放大电路、相位补偿电路、电流限制电路等构成的CMOS升压型DC/DC LED驱动。由于内置了低导通电阻的增强型N沟道功率MOSFET&#xff0c;因此适用于需要高效率、高输出电流的应用电路。另外&#xff0c;可通过在VSENSE端子连接电流…

使用Rust开发命令行工具

生成二进制文件&#xff0c;将其扔到环境变量的path下即可~ 用rust打造实时天气命令行工具[1] 找到合适的API 使用该api[2] 如请求 api.openweathermap.org/data/2.5/weather?qBeijing&appidyour_key: { "coord": { "lon": 116.3972, "lat&quo…

网络直播源码UDP协议搭建:为平台注入一份力量

网络直播源码中的UDP协议的定义&#xff1a; UDP协议又名用户数据报协议&#xff0c;是一种轻量级、无连接的协议。在网络直播源码平台中&#xff0c;UDP协议有着高速传输与实时性的能力&#xff0c;尤其是在网络直播源码实时性要求较高的场景&#xff0c;UDP协议的应用有着重要…

在项目中快速搭建机器学习的流程

在软件开发领域&#xff0c;机器学习框架发挥着关键作用&#xff0c;为开发人员提供强大的人工智能工具、库和算法&#xff0c;以有效地利用机器学习的潜力。从本质上讲&#xff0c;机器学习使计算机能够从数据中学习并做出预测或决策&#xff0c;而无需明确编程。 机器学习框…

CAN总线学习——物理层、数据链路层、CANopen协议

1、CAN总线介绍 1.1、CAN总线描述 (1)CAN总线支持多节点通信&#xff0c;但是节点不分区主从&#xff0c;也就是不存在一个节点来负责维护总线的通信&#xff1b;这点可以和I2C总线对对比&#xff0c;I2C是一主多从模式&#xff1b; (2)是差分、异步、串行总线&#xff0c;采用…

SHELL 基础 入门(三) Bash 快捷键 命令执行顺序,详解通配符

目录 Bash 常用快捷键 输入输出重定向 << 用法 输出重定向 命令执行顺序 ; 分号 && || 通配符 传统通配符 &#xff1f; * [ ] [ - ] [ ^ ] 常用字符 强调 &#xff1a; { } 生成序列 Bash 常用快捷键 Ctrl A 把光…

Unity3D Pico VR 手势识别 二

Unity3D Pico VR 手势识别_Cool-浩的博客-CSDN博客 此篇主要讲解怎么手势追踪&#xff0c;手势姿态自定义预制识别&#xff0c;不会导入SDK和配置环境的请看上一章节 环境要求 SDK 版本&#xff1a;2.3.0 及以上PICO 设备型号&#xff1a;PICO Neo3 和 PICO 4 系列PICO 设备系…

解密算法与数据结构面试:程序员如何应对挑战

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…