选择加编程,选择题考的范围挺广的,编程题第一题有点难度,第二题还好,复盘一下遇到的有点卡顿的题目。
1.排序问题
快速排序最适合排完全无序的数据,如果基本有序的数据反而会耗时比较长,原因在于这种情况下一般拿第一个数做基准值的话,容易出现按基准值分为两半后左右不平衡,会让一边的递归完全失效,发挥不出快速排序的优势。
而且因为是基本有序的,容易出现对已经排好序的数组进行无效的递归排序的情况。
快排必须先从右边指针开始的原因: 我们的目标是小于基准值的全去左边,大于基准值的全去右边,因为最后有个交换操作,如果是右边先开始,最后停留位置是小于基准值的,如果是左边先开始,最后左右相遇的是大于基准值的,大于基准值的这个数要和基准值交换,破坏了顺序
快排代码:
#include <iostream>
using namespace std;
void quicksort(int left, int right, int nums[]){
int key = left;//基准值下标
int curl = left;//左指针
int curr = right;//右指针
while(curl < curr){//这个判断条件是让程序在第一次交换后继续进行
//找右边第一个比基准值小的
while(curl < curr && nums[curr] >= nums[key]){
curr--;
}
//找左边第一个不符合要求,也就是比基准值大的,一样大的不用管,在之后的小数组里继续排序
while(curl < curr && nums[curl] <= nums[key]){
curl++;
}
if(curl < curr){//这时候curl前面的都是符合条件的, 3 2 4 ,curl指向4,我们需要交换3 和 2
swap(nums[curl],nums[curr]);
}else{
swap(nums[key],nums[curl]);
quicksort(left,curl-1,nums);
quicksort(curl+1,right,nums);
}
}
}
int main(){
int a[] = {10,2,4,5,1,8,7};
quicksort(0,6,a);
for(int num : a){
cout << num << " ";
}
}
2.python2函数参数格式
*arg 可变参数,参数不确定
arg = 9,直接确定好了参数的值,提供默认值
**arg 会把关键字参数转化为键值对,
3.java网络编程是在socket基础上的,而且是对ip、tcp协议都适用
4.软件开发模型:
- 边做边改模型
- 瀑布模型
- 快速原型模型
- 增量模型
- 螺旋模型
- 演化模型
- 喷泉模型
- 智能模型
- 混合模型
- RAD模型;
5.二分查找时间复杂度
二分查找是对半查找,查找次数x是总数n/2/2/2/2/2直到n为1的运算次数,所以2^x = n;时间复杂度x = 1og 2 n;
6.算法空间复杂度计算
7.辗转相除法求最大公约数的复杂度
辗转相除法思想:两个数m,n
1.得到m除以n的余数mod
2.将n作为新的被除数
2.将余数mod作为新的除数
……
重复以上过程,直至mod为0,此时的除数为最大公约数
代码实现:
#include <iostream>
#include <algorithm>
using namespace std;
int gcd(int a, int b){
return b==0 ? a : gcd(b,a%b);
}
int main(){
int res = gcd(346,897);
cout << res;
}
注意这里核心代码的参数的位置,因为要做一个旧除数转为被除数这样一个操作,所以传参的时候位置要换一下。
8.编程题
类似题目:1135. 最低成本联通所有城市,https://leetcode.cn/problems/connecting-cities-with-minimum-cost/
1.按成本(边长)来排序
2.按照排好的顺序,依次构图,如果要添加的边的两个端点都已经添加过了,就不再重复添加了,否则则需要添加进去。每次添加的时候成本增加。
class UnionFindSet
{
private:
vector<int>nums;
int count;
public:
UnionFindSet(int n){
count = n;
nums.resize(n+1);
for(int i = 1; i <= n; i++){
nums[i] = i;
}
}
int find(int x){
if(nums[x] == x){
return x;
}
return find(nums[x]);
}
int merge(int node1, int node2){
if(find(node1) == find(node2)){
return false;
}else{
nums[max(node1,node2)] = min(node1,node2);
count--;
return true;
}
}
bool isable(){
if(count == 2){
return true;
}else{
return false;
}
}
};
class Solution {
public:
int minimumCost(int n, vector<vector<int>>& connections) {
sort(connections.begin(), connections.end(), [](const auto &a, const auto &b) {
return a[2] < b[2];
});
UnionFindSet ufs(n);
int res = 0;
for(auto round : connections){
if(ufs.merge(round[0], round[1])){
res += round[2];
}
}
return ufs.isable() ? -1 : res;
}
};
但这个代码老是有一部分用例通过不了
我感觉的是问题出在联通集判断这
修改一下代码
class UFS{
private:
vector<int>set;
int count; //用来记录已经添加进去的节点数
int sumcost;
public:
//构造函数
UFS(int n){
count = n;
sumcost = 0;
set.resize(n+1);
}
//初始化集合
void setcrt(int n){
for(int i = 0; i <= n; i++){
set[i] = i;
}
}
//根据边关系梳理各节点之间关系
void unioncrt(int a, int b, int cost){
//第一种情况,两个点之前没有关系,统一用小的一个点做根
if(set[a] != set[b]){
int root = min(set[a],set[b]);//统一用这个去更新
int key = max(set[a],set[b]);//将根为key的全部变为根为root
for(int i = 0; i < set.size(); i++){
if(set[i] == key){
set[i] = root;
}
}
count--;
sumcost += cost;
}
}
//是否可以全部联通
bool isable(){
if(count > 1){
return false;
}else{
return true;
}
}
//最小花费
int getmincost(){
return sumcost;
}
};
class Solution {
public:
int minimumCost(int n, vector<vector<int>>& connections) {
sort(connections.begin(), connections.end(), [](const auto &a, const auto &b) {
return a[2] < b[2];
});
UFS u(n);
u.setcrt(n);
for(int i = 0; i < connections.size(); i++){
u.unioncrt(connections[i][0], connections[i][1], connections[i][2]);
}
if(u.isable()){
return u.getmincost();
}else{
return -1;
}
}
};
勉强过了,但这个时间复杂度。。。
主要是每次的遍历修改根比较耗时,后面做一下优化吧。