秋招算法高频算法笔试题

自己在秋招过程中遇到的算法笔试题,包含中大厂,都附解析!

汽水瓶

如果汽水瓶数目为1或者0,那么一瓶都喝不到
如果汽水瓶数目为2或者3,那么只能喝到一瓶
如果为2,喝到一瓶后手里一个瓶子都没有了,没法继续循环下去
如果为3,喝到一瓶后手里只剩一个瓶子,没法继续循环下去
如果汽水瓶数目大于3,每次耗费三个瓶子喝到一瓶,然后多了一个瓶子,即每一轮耗费两个瓶子

# include <iostream>
using namespace std;
unsigned int sln(unsigned int N){
    if (N == 2 || N == 3) {
        return 1;
    }
    if (N <= 1){
        return 0;
    }
    unsigned int Total = 0;
    while (N > 3) {
        N -= 2;
        Total++;
        if (N == 2)
        {
            Total++;
            N = 0;
        }
        if (N == 3)
        {
            Total++;
            N = 1;
        }
    }
    return Total;
}
int main(){
    unsigned int N;
    while (cin >> N) {
        if (N == 0) break;
        cout << sln(N) << endl;
    }
    return 0;
}

明明的随机数

//方法一: 暴力版本 
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main() {
    int n;
    cin>>n;
    int m;
    vector<int>v;
    while(n--){
        cin>>m;
        v.push_back(m);
    }
    sort(v.begin(),v.end());
    cout<<v[0]<<endl;
    for(int i=1;i<v.size();i++){
        if(v[i]!=v[i-1]){
          cout<<v[i]<<endl;
        }
    }
}
//方法二:STL(set)版本
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin>>n;
    int m;
    set<int>us;//插入有序
    while(n--){
        cin>>m;
        us.insert(m);
    }
    for(auto &i:us){
        cout<<i<<endl;
    }
}

**进制转换

**image.png

#include <iostream>
using namespace std;

int main() {
    int a;
    while (cin >> hex>> a) { // 注意 while 处理多个 case
        cout << a << endl;
    }
}

Words

image.png

#include<bits/stdc++.h>
using namespace std;

int main(){
    
    string str="";
    while(getline(cin,str)){
        int n=str.size();
        int countspace=0;
        double ans=0;
        for(int i=0;i<str.size();i++){
            if(str[i]==' '){
                countspace++;
            }        
        }
        ans=1.0*(n-countspace)/(1.0*(countspace+1));
        cout<<fixed<<setprecision(2)<<ans<<endl;
    }  
    return 0;
}

Vowel

image.png

#include<set>
#include<string>
#include<iostream>
using namespace std;

int main(){
    
    string str="";
    string ans="";
    set<char>se;
    se.insert('a');
    se.insert('e');
    se.insert('i');
    se.insert('o');
    se.insert('u');
    se.insert('A');
    se.insert('E');
    se.insert('I');
    se.insert('O');
    se.insert('U');
    while(getline(cin,str)){
        for(int i=0;i<str.size();i++){
            if(se.find(str[i])==se.end()){
                ans.push_back(tolower(str[i]));
            }
            else{
               ans.push_back(toupper(str[i]));  
            }
        }
        cout<<ans;       
    }  
    return 0;
}

计算字符串重新排列数

image.png

栈数据合并

image.png
image.png

整体代码

#include <iostream>
#include<stack>
#include <sstream>
using namespace std;

//没有消除时,栈里面大小一直是1
int main() {
    stack<int> s;
    string input;
    //输入:10 20 50 80 1 1
    //输出:2 160
    getline(cin, input);
    istringstream iss(input);//输入的一行挨个读取
    int num;
    while (iss >> num) {
        if (s.empty()) {
            s.push(num);
            continue;//关键
        }
        int sum = num;
        while (!s.empty() && s.top() <= num) {
            int top = s.top();
            s.pop();
            sum += top;
            if (sum == top * 2) {
                sum = top * 2;
                continue;//关键
            }
            if (!s.empty() && sum == top * 2 + s.top()) {
                sum = top * 2 + s.top();
                s.pop();
            }
            break;
        }
        s.push(sum);
    }
    while (!s.empty()) {
        cout << s.top() << " ";
        s.pop();
    }
    return 0;
}

寻找密码串

C++字符串转数字: stoi C语言字符串转数字:atoi(s.c_str())
C++数字转字符串to_string
image.png
image.png
image.png

整体代码

#include <iostream>
#include <string>
#include<set>
#include <algorithm>

using namespace std;

bool is_valid(string s) {
    return set<char>(s.begin(), s.end()).size() == 1;
}

int main() {
    string a, c;
    long long b;
    cin >> a >> b >> c;

    long long size = a.length();
    long long ans = 0;
    for (int i = 0; i < size; i++) {
        for (int len = 0; len < 13; len++) {
            if (i + len >= size) {
                break;
            }
            long long now = stoll(a.substr(i, len + 1));
            if (c == "+") {
                if (is_valid(to_string(now + b))) {
                    ans = max(ans, now);
                }
            }
            else if (c == "-") {
                if (is_valid(to_string(now - b))) {
                    ans = max(ans, now);
                }
            }
            else {
                if (is_valid(to_string(now * b))) {
                    ans = max(ans, now);
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

染色服务器,最短耗费时间走完所有的服务器-5.10

image.pngimage.pngimage.png

#include <iostream>
#include <queue>
#include <vector>
#include <unordered_map>
#include <climits>

using namespace std;

int main() {
    int n;
    cin >> n;//几个服务器

    int m;
    cin >> m;//几条路径

    unordered_map<int, int> sysTime;
    unordered_map<int, vector<pair<int, int>>> nxs;

    //m条路径从哪到哪,耗时多久
    for (int i = 0; i < m; i++) {
        int s, d, t;
        cin >> s >> d >> t;

        if (s != d)
            nxs[s].push_back({ d, t });
        else
            sysTime[s] = t;
    }
    //从哪个服务器开始
    int start;
    cin >> start;

    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> h;
    h.push({ 0, start });

    vector<int> dis(n + 1, INT_MAX);
    dis[start] = 0;

    while (!h.empty()) {
        int time = h.top().first;
        int node = h.top().second;
        h.pop();

        for (auto& nx : nxs[node]) {
            int nxNode = nx.first;
            int nxTime = nx.second;

            if (dis[nxNode] > time + sysTime[nxNode] + nxTime) {
                h.push({ time + sysTime[nxNode] + nxTime, nxNode });
                dis[nxNode] = min(dis[nxNode], time + sysTime[nxNode] + nxTime);
            }
        }
    }

    int cnt = 0, res = 0;
    for (int d : dis) {
        if (d != INT_MAX) {
            cnt++;
            res = max(res, d);
        }
    }

    cout << cnt << " " << res << endl;

    return 0;
}

小美的送花路线

image.png
根据题设,考虑树状结构。求:
sum1:从花店到所有客户地址的距离之和;
sum2:骑手实际走的最短路程,且最后一趟不需再返回。

求sum1:
根据输入的u、v、w,对于任意节点都能写出dp[v]=dp[u]+w,从而得到sum1。
对于例子1来说,sum1+=dp[v]。如dp[5]=dp[2]+1=3+1=4。sum1=3+1+2+4=10。

求sum2:
要求最短路径,根据最后一趟不需返回,可知最后一趟一定是从花店到最远的客户地址处,这部分距离只需计算一次,其余的到其他客户地址的距离需要计算往返路程。因此sum2+=2×w,还要-maxlen,其中maxlen是dp[v]中的最大值。
对于例子1来说,离花店最远的客户地址是5,路程中还途径了客户1。因此,sum2=2×(3+1+2+1)-(3+1)=10。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(){
    int n;
    cin>>n;
    vector<int>dp(n,0);
    int sum1 = 0,maxlen = 0,sum2 = 0;
    int u,v,w;
    for(int i=0;i<n-1;i++){
        cin>>u>>v>>w;
        dp[v] = dp[u]+w;
        sum2 += w*2;
        maxlen = max(dp[v],maxlen);
        sum1 += dp[v];
    }
    cout << sum1 << " " << sum2-maxlen;
}

小美的评分计算器

需注意的点:
①输入的是1星到5星的评价的数量;
②两个整数相除还是整数,需要用强制转换成小数;
③需要考虑输出为0.0的情况。
④不四舍五入的小数去尾的实现:乘整十(一位小数)向下取整再除十,使用fixed和setprecision控制实数部分及小数部分精度

fixedsetprecision 是用来控制输出浮点数精度和格式的两个重要工具。
fixed 是一个 C++ 标准库中的输出流修饰符,它用于指示输出的浮点数使用定点表示法而非默认的科学计数法。使用 fixed 后,输出的浮点数会以固定的小数位数格式进行输出。
fixed 是一个全局性质的修饰符,一旦使用,它会一直生效,直到被另外的修饰符覆盖为止。
setprecision 是另一个输出流修饰符,用于指定输出浮点数的小数位数。

向上取整:ceil,向下取整:floor,四舍五入:round

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n1,n2,n3,n4,n5;
	cin>>n1>>n2>>n3>>n4>>n5;
	double rate = 0;
	rate = (double)(1*n1+2*n2+3*n3+4*n4+5*n5)/(n1+n2+n3+n4+n5);
	if(n1==0&&n2==0&&n3==0&&n4==0&&n5==0){
		cout<<"0.0";
	}
	else{
		cout<<fixed<<setprecision(1)<<floor(rate*10.0)/10.0; 
	}
}

小美的外卖省钱计划

#include <iostream>
using namespace std;

int main() {
    int n;
    cin>>n;
    int x=0, y=0;
    int sum1=0,sum2=0;
    for(int i=0;i<n;i++){
       cin>>x>>y;
       if(x>y){
          sum2+=(x-y);
          sum1+=x;
       }
       else{
          sum1+=y;
       }
    }
    cout<<sum1<<" "<<sum2;
}

小美的代金券要过期啦

例子中是从后向前进行消消乐的,因此考虑使用栈结构,将序列元素入栈后,当栈顶元素和序列中元素相等时,将输入的x+1。

#include<bits/stdc++.h>
using namespace std;
	
int main(){	
	int n;
	int x = 0;
	cin>>n;
	int* s = new int[n];
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
	}
	stack<int> nums;
	nums.push(s[0]);
	for(int i=1;i<n;i++){
		while(!nums.empty()&&s[i]==nums.top()){
			nums.pop(); 
			s[i]++;
			x++;
		} 
		nums.push(s[i]);
	}
	cout<<x;
}

字符分割

如给你一串字符“path=/chat.openai.com, language=c++, path=baidu.com",
输入 2 path language,输出 baidu.com c++

#include<iostream>
#include<vector>
#include<string>
#include<unordered_map>

using namespace std;

int main() {
    string str;
    getline(cin, str);
    unordered_map<string, string> mmap;
    //字符分割
    for (int i = 0; i < str.size(); i++) {
        int start = i;
        while (start < str.size() && str[start] != '=') {
            start++;
        }
        string str2 = str.substr(i, start - i);
        int start2 = start + 1;
        while (start2 < str.size() && str[start2] != ',') {
            start2++;
        }
        string str3 = str.substr(start + 1 , start2 - start - 1);
        i = start2;
        //此处说相同的key取后者的value,应该直接替代是没有问题的
        mmap[str2] = str3;
    }
    //输入验证
    int n;
    cin >> n;
    string str4;
    vector<string> vec;
    while (n > 0 && cin >> str4) {
        vec.push_back(str4);
        n--;
    }
    for (string& strTmp : vec) {
        if (mmap.count(strTmp) >= 1) {
            cout << mmap[strTmp] << endl;
        }
        else {
            cout << "EMPTY" << endl;
        }
    }
    return 0;
}

美味值数组

给你一个每一天糖果的美味值数组,只能隔天吃,但也可以反悔,有K次反悔机会

  • 思路:先用打家劫舍的方法,然后对没有选的取k个最大值
#include<iostream>
#include<vector>
#include<string>
#include<unordered_map>
#include<queue>

using namespace std;
int maxTaste(int k, vector<int>& vec) {
    int len = vec.size();
    vector<int> dp(len);
    dp[0] = vec[0];
    if (len == 1) {
        return dp[0];
    }
    vector<bool> used(len, false);
    if (len >= 2) {
        dp[1] = max(dp[0], vec[1]);
        if (len == 2) {
            if (k > 0) {
                return vec[0] + vec[1];
            }
            else {
                return dp[1];
            }
        }
    }
    for (int i = 2; i < len; i++) {
        dp[i] = max(dp[i - 2] + vec[i], dp[i - 1]);
    }
    //判断最后一个选了没
    bool jus;
    if (dp[len - 3] + vec[len - 1] > dp[len - 2]) {
        jus = true;
    }
    else {
        jus = false;
    }
    priority_queue<int, vector<int>, less<int>> pq;
    if (!jus) {
        for (int i = len - 1; i > 0; i = i - 2) {
            pq.push(vec[i]);
        }
    }
    else {
        for (int i = len - 2; i > 0; i = i - 2) {
            pq.push(vec[i]);
        }
    }
    int res = dp[len - 1];
    for (int i = 0; i < k; i++) {
        res += pq.top();
        pq.pop();
    }
    return res;
}

int main() {
    //反悔次数
    int k;
    cin >> k;
    //输入美味值
    int n;  //天数
    cin >> n;
    vector<int> vec;
    int  num;
    while (n > 0 && cin >> num) {
        vec.push_back(num);
        n--;
    }
    cout << maxTaste(k, vec) << endl;
    return 0;
}

0-1背包问题

n块巧克力板,边长为a[i], 重量为a[i]*a[i], m 个背包, 可以装重量为b[i], 求每个背包最多可以装多少?

  • 思路: 可以对巧克力板按重量从小到大排序,前缀和即可
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>

using namespace std;

int large(vector<int>& a, int b) {
    int sum = 0;
    int len = a.size();
    int i;
    for (i = 0; i < len; i++) {
        sum += a[i];
        if (sum > b) {
            break;
        }
    }
    return i;
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<int> a, b;
    int ins;
    while (n > 0 && cin >> ins) {
        a.push_back(ins * ins);
        n--;
    }
    while (m > 0 && cin >> ins) {
        b.push_back(ins);
        m--;
    }
    sort(a.begin(), a.end());
    for (int tmp : b) {
        cout << large(a, tmp)<< " ";
    }
    cout << endl;

    return 0;
}

用O(n)写一个数组的第K大数

快速选择算法的基本思想是通过每次选取一个基准元素,将数组分为两个部分,小于基准元素的部分和大于基准元素的部分。然后根据基准元素所在位置和K的关系,决定在哪个部分继续查找

#include <iostream>
#include <vector>

// 快速选择算法
int quickSelect(std::vector<int>& nums, int left, int right, int k) {
    // 选取基准元素
    int pivot = nums[left];
    int i = left + 1;
    int j = right;

    // 将大于基准元素的数移到右侧,小于基准元素的数移到左侧
    while (i <= j) {
        if (nums[i] < pivot && nums[j] > pivot) {
            std::swap(nums[i], nums[j]);
            i++;
            j--;
        }
        if (nums[i] >= pivot) {
            i++;
        }
        if (nums[j] <= pivot) {
            j--;
        }
    }

    // 将基准元素放在正确的位置
    std::swap(nums[left], nums[j]);

    // 判断基准元素的位置与K的关系
    int pos = j - left + 1;
    if (pos == k) {
        return nums[j];
    }
    else if (pos > k) {
        return quickSelect(nums, left, j - 1, k);
    }
    else {
        return quickSelect(nums, j + 1, right, k - pos);
    }
}

// 找出数组的第K大数
int findKthLargest(std::vector<int>& nums, int k) {
    int n = nums.size();
    return quickSelect(nums, 0, n - 1, k);
}

int main() {
    std::vector<int> nums = { 3, 1, 5, 2, 4 };
    int k = 2;
    int kthLargest = findKthLargest(nums, k);
    std::cout << "第" << k << "大数是:" << kthLargest << std::endl;
    return 0;
}

合并有序数组

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int p1=m-1;
        int p2=n-1;
        int tail=p1+p2+1;
        int cur;
        while(p1>=0||p2>=0){
          if(p1==-1){
            cur=nums2[p2--];
          }
          else if(p2==-1){
            cur=nums1[p1--];
          }
          else if(nums1[p1]>nums2[p2]){
             cur=nums1[p1--];
          }
          else{
             cur=nums2[p2--];
          }
          nums1[tail--]=cur;
        }
    }
};

输入一堆数,每个数都是出现 4 次,只有一个数出现三次,找出这个数。时间复杂度 O(nlogn),空间复杂度 O(logn)

1)手撕快排再遍历
2)一直异或,最后异或的结果一定是那个数

#include<iostream>
#include<vector>
using namespace std;
//时间复杂度O(N)
int main() {
	vector<int>nums{ 1,1,1,1,2,2,2,3,3,3,3,6,6,6,6,5,5,5,5};
	int ans = nums[0];
	for (int i = 1; i < nums.size(); i++) {
		ans = ans ^ nums[i];
	}
	cout << ans << endl;
	return 0;
}

手写生产者消费者模型

为应对系统的通信上消息收发的高耦合度,在接受和发送消息后设计一个缓存队列,并使用多线程生产者-消费者来进行收发解耦。避免通信上的拥堵情况。

class MyTest{
private:
  std::deque<T> queue_; //缓存队列
  size_t size_limit_;  //缓存队列大小的限制
  std::mutex lock_;  //互斥锁
  std::condition_variable empty_, full_;  //并发条件变量类

  std::atomic<int> producer_num_;  //生产者数量
};

实现思路是:当缓存队列满的时候,生产者将被挂起,直到队列重新拥有空间。但缓存队列为空时,消费者线程将被挂起,直到有“商品”被放入队列之中。

void Productor(T& item) {
    {
      std::unique_lock<std::mutex> lk(lock_); //加锁防止冲突
      while (queue_.size() >= size_limit_) {
        full_.wait(lk);
      }
      queue_.emplace_back(item);
    }
    empty_.notify_one();
}

full_.wait(lk)在queue队列满时将会把Productor挂起,直到queue有空间放入新的item。notify_one方法任意从WAITTING状态的线程中挑选一个进行通知,使得调用wait()方法的线程从等待队列移入到同步队列中,等待有机会再一次获取到锁,从而使得调用wait()方法的线程能够从wait()方法处退出。

bool Consumer(T& item) {
    {
      std::unique_lock<std::mutex> lk(lock_);
      while (queue_.empty() && (producer_num_ != 0)) {
        empty_.wait(lk);
      }
      if (queue_.empty() && (producer_num_ == 0)) {
        return false;
      } else {
        item = std::move(queue_.front());
        queue_.pop_front();
        full_.notify_one();
        return true;
      }
    }
  }

同理,empty_.wait(lk)会在生产者数量为0或者队列queue为空的时候,将Consumer挂起。直到有商品进入到队列中。这样就可以实现一个简单的生产者消费者。

二叉树层序遍历

 vector<vector<int>> levelOrder(TreeNode*root) {
    queue<TreeNode*>que;
    if(root==NULL) return root;
    que.push(root);
    vector<vector<int>>ans;
    while(!que.empty()){
        int n=que.size();
        vector<int>path;
        for(int i=0;i<n;i++){
            TreeNode*node=que.front();
            que.pop_back();
            path.push_back(node->val);
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        ans.push_back(path);
    }
    return ans;
}

输入高维张量,返回shape

import numpy as np
def get_shape(tensor):
    shape = np.shape(tensor)
    return shape
# 示例输入一个3维张量
tensor = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
shape = get_shape(tensor)
print(shape)
#include <iostream>
#include <vector>
using namespace std;

template<typename T>
vector<size_t> getShape(const vector<T>& tensor) {
    vector<size_t> shape;
    size_t size = tensor.size();
    while (size > 0) {
        shape.push_back(size);
        size /= tensor[0].size();
    }
    return shape;
}

int main() {
    vector<vector<vector<int>>> tensor{
        {{1, 2}, { 3, 4 }},
        { {5, 6}, {7, 8} }
    };
    vector<size_t> shape = getShape(tensor);
    cout << "Shape: ";
    for (size_t dim : shape) {
        std::cout << dim << " ";
    }
    cout << std::endl;
    return 0;
}

GPU内存结构

  1. 全局内存(Global Memory):全局内存是GPU中最大的内存池,通常具有较大的容量。它用于存储核心数据结构、变量和计算结果等。全局内存对于所有线程可见,但相对于其他内存层级而言,它的访问速度较慢。
  2. 共享内存(Shared Memory):共享内存是位于GPU的多处理器(Multiprocessor)中的每个线程块(Thread Block)之间共享的内存区域。它的访问速度非常快,可以在同一线程块的线程之间共享数据。共享内存主要用于线程之间的通信和协作,以提高性能。
  3. 常量内存(Constant Memory):常量内存用于存储在执行期间不会发生改变的常量数据。它在访问速度上比全局内存快,但容量较小。常量内存对于所有线程可见,可以通过缓存机制提高访问效率。
  4. 纹理内存(Texture Memory):纹理内存是专门用于图形渲染的内存区域,具有高速缓存和过滤器等功能。它主要用于存储纹理数据,并提供一些特殊的访问方式,如双线性插值和边界处理等。
  5. 寄存器文件(Register File):寄存器文件是GPU中每个线程的私有内存空间。它用于存储线程的局部变量、中间计算结果和函数调用参数等。寄存器的访问速度非常快,但容量有限。对于某些计算密集型任务,寄存器的使用可能需要精心管理以避免资源耗尽。

CUDA三维结构好还是二维好

CUDA(Compute Unified Device Architecture)是NVIDIA提供的用于GPU编程的并行计算平台和编程模型。在CUDA中,既可以使用二维结构(二维线程块和二维网格)也可以使用三维结构(三维线程块和三维网格)。选择使用二维还是三维结构取决于问题的特性和并行计算的需求。
二维结构:

  • 二维结构适用于处理具有二维或类似矩阵的数据结构。例如,图像处理中的像素数据可以组织为二维数组,因此使用二维结构可以方便地处理图像。
  • 二维结构可以更好地利用数据的空间局部性。相邻的线程可以访问相邻的数据,这有助于减少全局内存访问和数据传输的次数,提高数据访问的效率。
    三维结构:
  • 三维结构适用于处理具有三维特性的数据结构,例如体积数据或具有复杂三维结构的数据集。
  • 使用三维结构可以更好地描述和组织三维数据,提高代码的可读性和可维护性。
  • 在某些情况下,三维结构可以提供更好的并行计算的均匀性和负载平衡,特别是当问题具有三维的均匀性或对称性时。
    总体而言,选择二维结构还是三维结构应根据问题的特性、数据的组织方式以及并行计算的需求来决定。如果问题可以自然地映射到二维结构,并且能够充分利用二维数据的空间局部性,那么二维结构可能更合适。如果问题具有三维特性或需要更好的均匀性和负载平衡,则可以考虑使用三维结构。在实际使用中,可以通过实验和性能分析来确定最适合问题的结构。

tensor core 了解吗

Tensor Core提供了高度优化的矩阵乘法和累积运算功能,能够在相对较短的时间内执行大规模矩阵运算,从而加速深度学习模型的训练和推理过程。
Tensor Core的主要特点包括:

  1. 数值精度:Tensor Core支持半精度浮点数(FP16)运算,它将浮点运算的计算精度降低一半,但同时大大增加了计算性能。在深度学习中,使用半精度计算通常可以满足训练和推理的准确性要求,能够显著提升计算速度。
  2. 矩阵乘法:Tensor Core使用特定的算法和硬件电路来加速矩阵乘法运算,尤其是小批量(mini-batch)矩阵乘法。它能够同时执行多个矩阵乘法操作,并且支持半精度累积运算,使得在一个时钟周期内可以完成更多的计算。
  3. 混合精度计算:Tensor Core可以与其他精度计算单元结合使用,如32位浮点数(FP32)和整数计算单元。这种混合精度计算的方法能够在保持准确性的同时提高计算性能,常用于深度学习的训练和推理过程。
    Tensor Core广泛应用于深度学习框架和库,如TensorFlow和PyTorch等,以加速深度神经网络的计算。它可以显著提高模型训练的速度,并在一定程度上降低对计算资源的需求。然而,使用Tensor Core需要特定的软件支持和配置,以确保正确地利用它的性能优势。

ReduceSum怎么优化

  1. 数据布局优化:调整数据的布局方式,以便在内存访问和数据传输方面更加高效。例如,优化数据的连续性和缓存友好性,可以利用缓存和向量化指令集提高访问效率。
  2. 并行化:使用并行计算技术,如线程、向量化和GPU并行处理等,将ReduceSum操作分布到多个计算单元上并发执行,以提高计算效率。
    3.** 数据复用**:尽可能地复用数据,减少不必要的读取和写入操作。可以通过共享内存、寄存器或缓存等机制来缓存中间计算结果,以减少数据的重复读取和写入。
  3. 剪枝和分解:对于大规模ReduceSum操作,可以考虑使用剪枝和分解等技术将其分解为更小的子任务,以降低每个子任务的计算负载,并充分利用并行性。
  4. 异步计算:使用异步计算技术,如CUDA流或异步任务队列,将ReduceSum操作与其他计算任务重叠,以充分利用计算和数据传输之间的隐藏延迟,提高整体性能。
  5. 内存访问优化:通过合理地利用局部性原则、数据对齐和访问模式等技术,优化内存访问方式,减少数据传输次数和延迟,提高数据吞吐量。
  6. 分级存储:对于大规模ReduceSum操作,可以使用分级存储策略,将数据分为多个层级,并使用不同的存储介质来适应不同的访问需求。例如,结合全局内存、共享内存和寄存器等多级存储来提高性能。
  7. 算法选择:根据实际需求,选择适合的ReduceSum算法。不同的算法可能有不同的计算复杂度和内存访问模式,选择合适的算法可以提高性能。

异构设备内存局部性怎么优化

  1. 内存访问模式优化:调整数据的访问模式,以提高内存局部性。例如,尽量保证线程对内存的访问是连续的、对齐的,避免随机的、不规则的内存访问。
  2. 数据布局优化:重组数据的存储方式,以提高内存局部性。例如,将相关的数据项存储在相邻的内存位置,或者使用数据结构和算法来组织数据,以充分利用局部性原则。
  3. 数据复用:尽量复用已经从内存加载到高速缓存的数据,减少对主存的访问。可以使用缓存、共享内存或寄存器等层级存储来存储中间计算结果,以避免重复的内存访问。
  4. 数据预取:利用硬件的数据预取机制,提前将需要使用的数据从主存加载到高速缓存,以减少访问延迟。可以使用编译器指令、预取指令或手动编码来控制数据的预取行为。
  5. 空间局部性优化:利用数据的空间局部性原则,以减少数据的移动和传输。例如,通过使用局部变量、循环展开、数据重用等技术来减少内存的读写操作。
  6. 访问模式分析和优化:通过对代码进行访问模式分析,了解内存访问的模式和特点,进而针对性地进行优化。可以使用工具、分析器或性能剖析器来帮助确定访问模式和性能瓶颈,并针对性地进行优化。
  7. 数据压缩和存储优化:在某些情况下,可以使用数据压缩技术来减少内存占用和传输带宽。通过压缩算法、数据压缩库或自定义的数据存储方案等方式,将数据压缩后存储在内存中,然后在需要使用时进行解压缩。

K 个一组翻转链表

image.png
image.png
image.png
image.png
image.png

class Solution {
public:
// 翻转一个子链表,并且返回新的头与尾
pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail) {
    ListNode* prev = tail->next;
    ListNode* p = head;
    while (prev != tail) {
        ListNode* nex = p->next;
        p->next = prev;
        prev = p;
        p = nex;
    }
    return {tail, head};
}

ListNode* reverseKGroup(ListNode* head, int k) {
    ListNode* hair = new ListNode(0);
    hair->next = head;
    ListNode* pre = hair;

    while (head) {
        ListNode* tail = pre;
        // 查看剩余部分长度是否大于等于 k
        for (int i = 0; i < k; ++i) {
            tail = tail->next;
            if (!tail) {
                return hair->next;
            }
        }
        ListNode* nex = tail->next;
        // 这里是 C++17 的写法,也可以写成
        // pair<ListNode*, ListNode*> result = myReverse(head, tail);
        // head = result.first;
        // tail = result.second;
        tie(head, tail) = myReverse(head, tail);
        // 把子链表重新接回原链表
        pre->next = head;
        tail->next = nex;
        pre = tail;
        head = tail->next;
    }
    return hair->next;
  }
};

最长回文子串:中心扩散法

class Solution {
public:
    pair<int, int> expandAroundCenter(const string& s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            --left;
            ++right;
        }
        return {left + 1, right - 1};
    }

    string longestPalindrome(string s) {
        int start = 0, end = 0;
        for (int i = 0; i < s.size(); ++i) {
            auto [left1, right1] = expandAroundCenter(s, i, i);
            auto [left2, right2] = expandAroundCenter(s, i, i + 1);
            if (right1 - left1 > end - start) {
                start = left1;
                end = right1;
            }
            if (right2 - left2 > end - start) {
                start = left2;
                end = right2;
            }
        }
        return s.substr(start, end - start + 1);
    }
};

字符串首次出现3次的字符

哈希表就行,遍历字符串,存放在map中,并判断value==3就返回key

#include<iostream>
#include<unordered_map>
using namespace std;

string str;
cin>>str;
unordered_map<char,int>um;
for(auto &i:str){
    um[i]++;
    if(i.second==3){
        cout<<i.first<<endl;
    }
}

数组中只出现一次的数字

//时间复杂度O(n)
//空间复杂度O(n)
#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int,int>mp;
        int ans=0;
        for(auto &i:nums){
            mp[i]++;
        }  
        for(auto &i:mp){
            if(i.second==1){
                ans=i.first;
            }
        }

        //for(auto &[key,value]:mp){
        //    if(value==1){
        //        ans=key;
        //        break;
        //    }
        //}
        return ans;
    }
};

合并2个有序数组

法一排序

将nums2放到nums1中,直接排序

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
       for(int i=0;i<n;i++){
          nums1[m++]=nums2[i];       
       }
       sort(nums1.begin(),nums1.end());
    }
};

法二,双指针

逆向双指针,尾部覆盖

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int p1=m-1,p2=n-1;
        int tail=m+n-1;
        while(p1>=0||p2>=0){
           if(p1==-1){
              nums1[tail--]=nums2[p2--];
           }
           else if(p2==-1){
              nums1[tail--]=nums1[p1--];
           }
           else if(nums1[p1]<nums2[p2]){
              nums1[tail--]=nums2[p2--];
           }
           else{
               nums1[tail--]=nums1[p1--];
           }
        }
    }
};

435.不重叠区间

先计算不重叠的区间数,然后用总的区间数—重叠的=要去掉的,记得自定义排序规则

class Solution {
public:
    /// static bool cmp(vector<int>&a,vector<int>&b){
    //    return a[1]<b[1];
    //}

    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
       //sort(intervals.begin(),intervals.end(),cmp);
       sort(intervals.begin(),intervals.end(),[](const auto &a,const auto &b){
           return a[1]<b[1];
       });
       int count=1;
       int right=intervals[0][1];
       for(int i=1;i<intervals.size();i++){
           if(intervals[i][0]>=right){
             count++;
             right=intervals[i][1];
           }
       }
       return intervals.size()-count;
    }
};

73.矩阵置零

2个标记数组,如果有元素为0,元素所在的行列所对应的标记数组的位置置true,用标记数组更新原数组

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m=matrix.size();
        int n=matrix[0].size();
        vector<bool>row(m),col(n);
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(!matrix[i][j]){
                   row[i]=col[j]=true;
                }
            }
        }     
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(row[i]||col[j]){
                   matrix[i][j]=0;
                }
            }
        }

    }
};

分割字符串,知道字符数量

输入一个字符串,求[“xiao”,“mi”]的组和有多少种
比如 输入:“I love xiaomi, I think mi com is the best"
输出:2
计算输入字符串中指定子字符串组的数量

#include <iostream>
#include <vector>
#include <string>

//s输入字符串
int countSubstringGroups(const std::string& s, const std::vector<std::string>& substrings) {
    int count = 0;
    size_t startIndex = 0;

    while (true) {
        bool found = false;
        //遍历目标串
        for (const auto& substring : substrings) {
            size_t index = s.find(substring, startIndex);
            if (index != std::string::npos) {
                found = true;
                startIndex = index + substring.length();
                break;
            }
        }

        if (!found) {
            break;
        }

        bool allNotFound = true;
        for (const auto& substring : substrings) {
            if (s.find(substring, startIndex) != std::string::npos) {
                allNotFound = false;
                break;
            }
        }

        if (allNotFound) {
            count++;
        }
    }

    return count;
}

int main() {
    // 输入字符串
    std::string inputStr = "I love xiaomi, I think mi com is the best";

    // 目标子字符串列表
    std::vector<std::string> targetSubstrings = {"xiao", "mi"};

    // 计算组数
    int result = countSubstringGroups(inputStr, targetSubstrings);

    // 输出结果
    std::cout << result << std::endl;

    return 0;
}

划分3*3矩阵

有一个m*n的字符矩阵,
要求:3*3的连续子矩阵里面x,a,o,m至少出现1次,i至少出现2次
求这样的3*3的矩阵有多少?

比如输入4*4的话
x i a q
o i m e
x a i c
c a d f


输出结果为2,有2个符合条件的连续子矩阵
x i a 
o i m 
x a i

o i m 
x a i 
c a d 

#include <iostream>
#include <vector>

using namespace std;

bool isValidSubmatrix(const vector<vector<char>>& matrix, int startRow, int startCol) {
    int count_x = 0, count_a = 0, count_o = 0, count_m = 0, count_i = 0;

    for (int i = startRow; i < startRow + 3; ++i) {
        for (int j = startCol; j < startCol + 3; ++j) {
            char currentChar = matrix[i][j];
            if (currentChar == 'x') count_x++;
            else if (currentChar == 'a') count_a++;
            else if (currentChar == 'o') count_o++;
            else if (currentChar == 'm') count_m++;
            else if (currentChar == 'i') count_i++;
            else{
                continue;
            }
        }
    }

    return (count_x >= 1 && count_a >= 1 && count_o >= 1 && count_m >= 1 && count_i >= 2);
}

int countSubmatrices(const vector<vector<char>>& matrix) {
    int m = matrix.size();
    int n = matrix[0].size();
    int count = 0;

    for (int i = 0; i < m - 2; ++i) {
        for (int j = 0; j < n - 2; ++j) {
            if (isValidSubmatrix(matrix, i, j)) {
                count++;
            }
        }
    }

    return count;
}

int main() {
    // 示例 4x4 的字符矩阵
    vector<vector<char>> matrix = {
        {'x', 'i', 'a', 'q'},
        {'o', 'i', 'm', 'e'},
        {'x', 'a', 'i', 'c'},
        {'c', 'a', 'd', 'f'}
    };

    int result = countSubmatrices(matrix);
    cout << "满足条件的3x3子矩阵数量为: " << result << endl;

    return 0;
}

42.接雨水

动态规划
1)统计每个下标左边的最大值,正向遍历
2)统计每个下标右边的最大值,反向遍历
3)计算每个下标的储水量,累加
image.png

//时间复杂度O(n)
//空间复杂度O(n)

class Solution {
public:
    int trap(vector<int>& height) {
        if(height.size()<=2) return 0;
        vector<int>leftHeight(height.size(),0);
        vector<int>rightHeight(height.size(),0);
        int size=rightHeight.size();

        leftHeight[0]=height[0];
        for(int i=1;i<size;i++){
            leftHeight[i]=max(height[i],leftHeight[i-1]);
        }

        rightHeight[size-1]=height[size-1];
        for(int i=size-2;i>=0;i--){
            rightHeight[i]=max(height[i],rightHeight[i+1]);
        }

        int sum=0;
        for(int i=0;i<size;i++){
            int h=min(leftHeight[i],rightHeight[i])-height[i];
            if(h>0) sum+=h;
        }
        return sum;
    }
};

有序链表

法一,先放到数组

class Solution 
{
public:
    ListNode* sortList(ListNode* head) 
    {
       if(head==nullptr) return head;
       vector<ListNode*>v;
       ListNode*cur=head;
       while(cur)
       {
           v.push_back(cur);
           cur=cur->next;
       }
       sort(v.begin(),v.end(),[](ListNode*a,ListNode*b){return a->val<b->val;});
       cur=v[0];
       for(int i=1;i<v.size();++i)
       {
           cur->next=v[i];
           cur=v[i];
       }
       cur->next=nullptr;
       return v[0];
    }
};

法二:合并2个有序链表,中点划分链表

class Solution 
{
public:
    ListNode* sortList(ListNode* head) 
    {
       return sortList(head,nullptr);
    }
    
    ListNode*sortList(ListNode*head,ListNode*tail)
    {
      if(head==nullptr)
      {
          return head;
      }
      if(head->next==tail)
      {
          head->next=nullptr;
          return head;
      }
      //找中点,以中点位2分界拆分成2个子链表,快慢指针
      ListNode*slow=head,*fast=head;
      while(fast!=tail)
      {
          slow=slow->next;
          fast=fast->next;
          if(fast!=tail)
          {
              fast=fast->next;
          }
      }
      ListNode*mid=slow;
      return merge(sortList(head,mid),sortList(mid,tail));
    }
     
    //合并两个有序链表
    ListNode*merge(ListNode*head1,ListNode*head2)
    {
      ListNode*dummyHead=new ListNode(0);
      ListNode*temp=dummyHead,*temp1=head1,*temp2=head2;
      while(temp1!=nullptr&&temp2!=nullptr)
      {
         if(temp1->val<=temp2->val)
         {
            temp->next=temp1;
            temp1=temp1->next;
         }
         else
         {
            temp->next=temp2;
            temp2=temp2->next;
         }
         temp=temp->next;
      }
      if(temp1!=nullptr)
      {
       temp->next=temp1;
      }
      if(temp2!=nullptr)
      {
       temp->next=temp2;
      }
      return dummyHead->next;
    }
};

一个数恰好等于它的因子之和

比如6=1+2+3,称为完数,问1-10000有多少个完数

#include <iostream>
#include <vector>

//找因子
std::vector<int> findFactors(int num) {
    std::vector<int> factors = {1};  // 1 是所有正整数的因子
    for (int i = 2; i <= num / 2; ++i) {
        if (num % i == 0) {
            factors.push_back(i);
        }
    }
    return factors;
}

//找出所有完数
std::vector<int> findPerfectNumbers(int limit) {
    std::vector<int> perfectNumbers;
    for (int num = 2; num <= limit; ++num) {
        if (std::find(perfectNumbers.begin(), perfectNumbers.end(), num) != perfectNumbers.end()) {
            continue;  // 避免重复计算已经找到的完数
        }
        std::vector<int> factors = findFactors(num);
        int sum = 0;
        for (int factor : factors) {
            sum += factor;
        }
        if (sum == num) {
            perfectNumbers.push_back(num);
        }
    }
    return perfectNumbers;
}

int main() {
    int limit = 10000;
    std::vector<int> perfectNumbersList = findPerfectNumbers(limit);

    std::cout << "在1到" << limit << "之间有" << perfectNumbersList.size() << "个完数,它们分别是:" << std::endl;
    for (int num : perfectNumbersList) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

大数相减

// 函数用于模拟字符串相加,包括进位处理
string addStrings(string num1, string num2) {
    int carry = 0;
    string result;
    
    // 让两个字符串等长,短的字符串前面补0
    int len = max(num1.length(), num2.length());
    num1 = string(len - num1.length(), '0') + num1;
    num2 = string(len - num2.length(), '0') + num2;

    for (int i = len - 1; i >= 0; i--) {
        int digit1 = num1[i] - '0';
        int digit2 = num2[i] - '0';

        int sum = digit1 + digit2 + carry;
        carry = sum / 10;
        result += to_string(sum % 10);
    }

    if (carry > 0) {
        result += to_string(carry);
    }

    reverse(result.begin(), result.end()); // 反转结果字符串
    return result;
}

浮点数相加

//字符串转浮点stod
//自定义函数用于将浮点数字符串转换为 double
double stringToDouble(const std::string& str) {
    double result = 0.0;
    bool isNegative = false;
    bool isFraction = false;
    double fractionMultiplier = 0.1;

    for (char ch : str) {
        if (ch == '-') {
            isNegative = true;
        } else if (ch == '.') {
            isFraction = true;
        } else {
            if (isFraction) {
                result += (ch - '0') * fractionMultiplier;
                fractionMultiplier *= 0.1;
            } else {
                result = result * 10 + (ch - '0');
            }
        }
    }

    return isNegative ? -result : result;
}

统计元音字母个数

对偶性质

class Solution {
public:
    long long countVowels(string word) {
        int n = word.size();
        unordered_set<char> vowels = {'a', 'e', 'i', 'o', 'u'};
        long long ans = 0;
        for (int i = 0; i < n; ++i) {
            if (vowels.count(word[i])) {
                ans += (long long)(i + 1) * (n - i);
            }
        }
        return ans;
    }
};

双链表模拟

假设双链表把一个 q 所指新结点作为非空双向链表中的 p 所指结点的前驱结点插入到该双链表中,算法步骤。

q->Link=p->prev;
p->Link=q;
q->Rink=p;
q->Link->Rlink=q;

输入的句子使用find函数找出NiuNiu,没有则输出-1;限定Python语言

input_sentence = input("请输入句子:")  # 获取用户输入的句子

# 使用find方法查找子字符串
index = input_sentence.find("NiuNiu")

if index != -1:
    print("NiuNiu 在句子中的索引是:", index)
else:
    print("NiuNiu 未在句子中找到")

字符串排序

2.给定几个字符串,请你分类,对于同一类字符串,可以通过N次交换其中的元素变为一样的,如ABCD和CDBA,不限定交换次数;

输入
4
ABCD
BCDA
ACBD
CDAB
输出
1

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>

int classifyStrings(std::vector<std::string> strings) {
    std::set<std::string> sortedStrings;
    
    for (const std::string& str : strings) {
        std::string sortedStr = str;
        std::sort(sortedStr.begin(), sortedStr.end());
        sortedStrings.insert(sortedStr);
    }
    
    return sortedStrings.size();
}

int main() {
    int n;
    std::cin >> n;
    std::vector<std::string> strings(n);

    for (int i = 0; i < n; i++) {
        std::cin >> strings[i];
    }
    int result = classifyStrings(strings);
    std::cout << result << std::endl;

    return 0;
}

105.岛屿的最大面积

class Solution {
    int dfs(vector<vector<int>>& grid, int cur_i, int cur_j) {
        if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1) {
            return 0;
        }
        grid[cur_i][cur_j] = 0;
        int di[4] = {0, 0, 1, -1};
        int dj[4] = {1, -1, 0, 0};
        int ans = 1;
        for (int index = 0; index != 4; ++index) {
            int next_i = cur_i + di[index], next_j = cur_j + dj[index];
            ans += dfs(grid, next_i, next_j);
        }
        return ans;
    }
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0;
        for (int i = 0; i != grid.size(); ++i) {
            for (int j = 0; j != grid[0].size(); ++j) {
                ans = max(ans, dfs(grid, i, j));
            }
        }
        return ans;
    }
};

641.双端队列模拟

class MyCircularDeque {
private:
    vector<int> elements;
    int rear, front;
    int capacity;

public:
    MyCircularDeque(int k) {
        capacity = k + 1;
        rear = front = 0;
        elements = vector<int>(k + 1);
    }

    bool insertFront(int value) {
        if (isFull()) {
            return false;
        }
        front = (front - 1 + capacity) % capacity;
        elements[front] = value;
        return true;
    }

    bool insertLast(int value) {
        if (isFull()) {
            return false;
        }
        elements[rear] = value;
        rear = (rear + 1) % capacity;
        return true;
    }

    bool deleteFront() {
        if (isEmpty()) {
            return false;
        }
        front = (front + 1) % capacity;
        return true;
    }

    bool deleteLast() {
        if (isEmpty()) {
            return false;
        }
        rear = (rear - 1 + capacity) % capacity;
        return true;
    }

    int getFront() {
        if (isEmpty()) {
            return -1;
        }
        return elements[front];
    }

    int getRear() {
        if (isEmpty()) {
            return -1;
        }
        return elements[(rear - 1 + capacity) % capacity];
    }   

    bool isEmpty() {
        return rear == front;
    }

    bool isFull() {
        return (rear + 1) % capacity == front;
    }
};

141.环形链表

判断是否有环

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode*slow=head,*fast=head;
        while(fast&&fast->next){
            slow=slow->next;
            fast=fast->next->next;
            if(slow==fast){
                return true;
            }
        }
        return false;
    }
};

142.环形链表 II

判断环的位置
相遇之后,slow指针回到出发点,一起走就行

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode*fast=head,*slow=head;
        while(fast!=NULL&&fast->next!=NULL){
          fast=fast->next->next;
          slow=slow->next;
          if(slow==fast){
                ListNode*cur=slow;
                ListNode*temp=head;
                while(cur!=temp){
                    temp=temp->next;
                    cur=cur->next;
                }
                return temp;
          }
        }
        return NULL;    
    }
};

怎么判断顺子5个

1)法一,先sort,然后遍历从第2个开始,看当前的是不是等于前一个+1
2)法二:放到set里面,判断最大值-最小值<5,且set的size=5

83.删除链表中的重复元素

1-2-2删除后为1-2
法一, 借助数组

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
       vector<int>ans;
       ListNode*cur=head;
       while(cur){
           ans.push_back(cur->val);
           cur=cur->next;
       }
       ans.erase(unique(ans.begin(),ans.end()),ans.end());
       ListNode*dummyNode=new ListNode(0);
       ListNode*now=dummyNode;
       for(int i=0;i<ans.size();i++){
           now->next=new ListNode(ans[i]);
           now=now->next;
       }
       return dummyNode->next;
    }
};

法二,一次遍历

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
       if(head==NULL||head->next==NULL){
           return head;
       }
       ListNode*cur=head;
       while(cur->next!=NULL){
         if(cur->val==cur->next->val){
             cur->next=cur->next->next;
         }
         else{
            cur=cur->next;
         }
       }
       return head;
    }
};

82.删除排序链表中的重复元素 II

删除链表中所有重复出现过的数,即1-2-2删除后为1

//一次遍历
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (!head) {
            return head;
        }
        
        ListNode* dummy = new ListNode(0, head);
        ListNode* cur = dummy;
        while (cur->next && cur->next->next) {
            if (cur->next->val == cur->next->next->val) {
                int x = cur->next->val;
                while (cur->next && cur->next->val == x) {
                    cur->next = cur->next->next;
                }
            }
            else {
                cur = cur->next;
            }
        }
        return dummy->next;
    }
};
//哈希集合
class Solution 
{
public:
    ListNode* deleteDuplicates(ListNode* head)
    {
       unordered_set<int>us;
       ListNode*s=head;
       //将链表中的重复元素的值放入哈希集合
       while(s!=NULL&&s->next!=NULL)
       {
           if(s->val==s->next->val)
               us.insert(s->val);               
            s=s->next;
       }
       //遍历链表,与哈希集合比较,重复则删除
       ListNode* prehead=new ListNode(-1);
       prehead->next=head;
       ListNode*pre=prehead;
       s=head;
       while(s!=NULL)
       {
           if(us.find(s->val)==us.end())//没有重复结点
           {
             s=s->next;
             pre=pre->next;         
           }
           else
           {
             pre->next=s->next;
             s=s->next; 
           }
           
       }
       return prehead->next;
    }
};

已经排好序的数组,找两个和为num的数字

//二分查找
//数组中的元素最多遍历一次,时间复杂度为 O(n*log(n))。
//只使用了两个额外变量,空间复杂度为 O(1)。
class Solution 
{
public:
    vector<int> twoSum(vector<int>& numbers, int target) 
    {
        for (int i=0;i<numbers.size();++i)
        {
            int low=i+1,high=numbers.size()-1;    //细节i+1    
            while(low<=high)
            {
                int mid=low+(high-low)/2;
                if(numbers[mid]==target-numbers[i])
                {
                    return {i+1,mid+1};
                }
                else if(numbers[mid]>target-numbers[i])
                {
                  high=mid-1;
                }
                else
                {
                  low=mid+1;
                }
            }
        }    
        return {-1,-1};
    }
};

补充知识

set_union并集

求两个有序序列的并集,合并结果包含所有的不重复元素,并拷贝到一个新的序列,前提是这两个序列的排序规则一样。

set_intersection交集

求两个有序序列的交集,合并结果是两个集合重合的元素,并拷贝到一个新的序列,前提是这两个序列的排序规则一样。

set_difference差集

求两个有序序列的差集,合并结果是在第一个集合中存在而在第二个集合中不存在的元素,并拷贝到一个新的序列,前提是这两个序列的排序规则一样。

set_symmetric_difference异或集

求两个有序序列的异或集,合并结果是两个序列合并后去除重合的元素,并拷贝到一个新的序列,前提是这两个序列的排序规则一样。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值