【优选算法】——leetcode——438.找到字符串中所有字母异位词

news2024/9/17 7:34:32

目录

1.题目

2.题目理解 

3.算法原理

1.如何快速判断两个字符串是否是异位词

2.解决问题 

暴力求解——>滑动窗口+哈希表

 滑动窗口

利用滑动窗口+哈希表解决问题 

 优化:更新结果的判断条件

4.编程代码 

C++代码

 1.频率统计

2. 双指针

 C语言代码

1.字符频率统计 

2.滑动窗口机制

3.判断窗口大小并维护窗口内字符频率

4.更新结果

C++知识点详解

1. STL(Standard Template Library)

2. 范围 for 循环

3. 字符数组与频率统计

4. 双指针(Sliding Window)技巧

5. 成员函数与类


 

ce6fbd68767d465bbe94b775b8b811db.png

731bd47804784fa2897220a90a387b28.gif

专栏:优选算法

 

1.题目

438. 找到字符串中所有字母异位词

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

 示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

提示:

  • 1 <= s.length, p.length <= 3 * 104
  • s 和 p 仅包含小写字母

2.题目理解 

“abc”的异位词 有:abc,acb,bac,bca,cab,cba;

 输出: [0,6](子串的起始索引)

3.算法原理

1.如何快速判断两个字符串是否是异位词

1.两个字符串都按照字符顺序排序,然后比较是否相等               排序+比较     nlogn +n       

2.统计每个字符出现的次数     哈希表遍历比较

2.解决问题 

暴力求解——>滑动窗口+哈希表

因为字符串p 的异位词的⻓度“m”⼀定与字符串p的⻓度相同,所以我们可以在字符串 s 中构
造⼀个⻓度为与字符串 p 的⻓度相同的滑动窗⼝,并在滑动中维护窗⼝中每种字⺟的数量;保持窗口大小一次遍历比较。

 滑动窗口

利用滑动窗口+哈希表解决问题 

可以⽤两个⼤⼩为 26 的数组来模拟哈希表,⼀个来保存 s 中的⼦串每个字符出现的个
数,另⼀个来保存 p 中每⼀个字符出现的个数。这样就能判断两个串是否是异位词。

 优化:更新结果的判断条件

利用变化量count来统计窗口中“有效字符的次数”;

当窗⼝中每种字⺟的数量与字符串p中每种字⺟的数量相同时,则说明当前窗⼝为字符串 p 
的异位词;

 

4.编程代码 

C++代码

class Solution
{
public:
vector<int> findAnagrams(string s, string p)
{
vector<int> ret;
int hash1[26] = { 0 }; // 统计字符串 p 中每个字符出现的个数
for(auto ch : p) hash1[ch - 'a']++;
int hash2[26] = { 0 }; // 统计窗⼝⾥⾯的每⼀个字符出现的个数
int m = p.size();
for(int left = 0, right = 0, count = 0; right < s.size(); right++)
{
char in = s[right];
// 进窗⼝ + 维护 count
if(++hash2[in - 'a'] <= hash1[in - 'a']) count++;
if(right - left + 1 > m) // 判断
{
char out = s[left++];
// 出窗⼝ + 维护 count
if(hash2[out - 'a']-- <= hash1[out - 'a']) count--;
}
// 更新结果
if(count == m) ret.push_back(left);
}
return ret;
}
};

 1.频率统计

for(auto ch : p) hash1[ch - 'a']++;
  • 范围 for 循环: 用于遍历字符串 p,并统计每个字符的出现次数。
  • 字符偏移量 ch - 'a': 将字符转换为数组索引,例如 'a' 对应 0'b' 对应 1

2. 双指针

  • 初始化指针和计数器 left, right, count: leftright 分别表示窗口的左边界和右边界,count 用于记录匹配字符的数量。
  • 滑动窗口 for 循环: 遍历字符串 s,右指针 right 不断向右移动。
  • 进窗口操作: 将 s[right] 加入窗口并更新频率数组 hash2。如果该字符的频率没有超过 hash1 中的频率,则计数器 count 加一。
  • 出窗口操作: 当窗口大小超过 m 时,将 s[left] 移出窗口,并更新频率数组 hash2 和计数器 count
  • 更新结果: 如果 count 等于 m,说明当前窗口是一个字母异位词,记录起始索引 left

 C语言代码

int* findAnagrams(char * s, char * p, int* returnSize) {
    int s_len = strlen(s);  // 使用 strlen 计算字符串 s 的长度
    int p_len = strlen(p);  // 使用 strlen 计算字符串 p 的长度
    int *ret = (int *)malloc(s_len * sizeof(int));
    *returnSize = 0;

    int hash1[26] = {0}; // 统计字符串 p 中每个字符出现的个数
    for (int i = 0; i < p_len; i++) {
        hash1[p[i] - 'a']++;
    }

    int hash2[26] = {0}; // 统计窗口里面的每一个字符出现的个数
    int count = 0;
    for (int left = 0, right = 0; right < s_len; right++) {
        char in = s[right];
        // 进窗口 + 维护 count
        if (++hash2[in - 'a'] <= hash1[in - 'a']) {
            count++;
        }

        // 判断窗口是否超过大小
        if (right - left + 1 > p_len) {
            char out = s[left++];
            // 出窗口 + 维护 count
            if (hash2[out - 'a']-- <= hash1[out - 'a']) {
                count--;
            }
        }

        // 更新结果
        if (count == p_len) {
            ret[*returnSize] = left;
            (*returnSize)++;
        }
    }

    return ret;
}

1.字符频率统计 

    int hash1[26] = {0}; // 统计字符串 p 中每个字符出现的个数
    for (int i = 0; i < p_len; i++) {
        hash1[p[i] - 'a']++;
    }
  • hash1:长度为26的整数数组,用于统计字符串p中每个字符的出现次数。hash1[i]表示字符'a' + i在字符串p中的出现次数。
  • 循环遍历字符串p,更新hash1数组。

2.滑动窗口机制

    int hash2[26] = {0}; // 统计窗口里面的每一个字符出现的个数
    int count = 0;
    for (int left = 0, right = 0; right < s_len; right++) {
        char in = s[right];
        // 进窗口 + 维护 count
        if (++hash2[in - 'a'] <= hash1[in - 'a']) {
            count++;
        }
  • hash2:长度为26的整数数组,用于统计滑动窗口内每个字符的出现次数。
  • count:记录当前滑动窗口内与字符串p中字符频率一致的字符数。
  • 滑动窗口通过right指针不断向右移动,将字符s[right]加入窗口,同时更新hash2数组和count计数。

3.判断窗口大小并维护窗口内字符频率

        // 判断窗口是否超过大小
        if (right - left + 1 > p_len) {
            char out = s[left++];
            // 出窗口 + 维护 count
            if (hash2[out - 'a']-- <= hash1[out - 'a']) {
                count--;
            }
        }
  • 检查滑动窗口的大小,如果窗口大小超过字符串p的长度(right - left + 1 > p_len),则需要移除窗口左侧的字符。
  • 更新left指针,移除窗口左侧字符,同时更新hash2数组和count计数。

4.更新结果

        // 更新结果
        if (count == p_len) {
            ret[*returnSize] = left;
            (*returnSize)++;
        }
    }

    return ret;
}
  • 如果count等于字符串p的长度,说明当前窗口内字符频率与字符串p一致,将left指针的值加入结果数组ret
  • 更新结果数组的大小*returnSize

C++知识点详解

  • STL(Standard Template Library): 向量 vector 是 STL 的一部分,提供动态数组的功能。
  • 范围 for 循环: C++11 引入的循环方式,简化了遍历操作。
  • 字符数组与频率统计: 使用数组来记录字符出现的频率,并进行简单的数学运算实现高效统计。
  • 双指针(Sliding Window)技巧: 通过两个指针控制一个窗口,用于高效地处理子串问题。
  • 成员函数与类: 通过类和成员函数组织代码,方便管理和调用。

1. STL(Standard Template Library)

向量 vector

概述vector 是 C++ 标准模板库(STL)中的一个动态数组,可以根据需要动态调整大小。

特点

  • 动态调整大小:vector 可以在运行时自动扩展和收缩。
  • 随机访问:支持使用索引进行随机访问,访问时间复杂度为 O(1)。
  • 内部实现:使用连续的内存块存储元素,类似于数组。

示例代码

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    // 添加元素到末尾
    vec.push_back(6);
    
    // 随机访问
    std::cout << "Element at index 2: " << vec[2] << std::endl;
    
    // 遍历向量
    for(int i : vec) {
        std::cout << i << " ";
    }
    
    return 0;
}

高级用法

插入和删除

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    // 在指定位置插入元素
    vec.insert(vec.begin() + 2, 99);
    
    // 删除指定位置的元素
    vec.erase(vec.begin() + 4);
    
    // 遍历向量
    for(int i : vec) {
        std::cout << i << " ";
    }
    
    return 0;
}

 

 动态调整大小

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec(5, 10); // 创建一个大小为5的向量,初始值为10
    
    vec.resize(10, 20); // 调整向量大小为10,新增的元素值为20
    
    for(int i : vec) {
        std::cout << i << " ";
    }
    
    return 0;
}

2. 范围 for 循环

概述:范围 for 循环是 C++11 引入的一种简化遍历容器的方式。

特点

  • 简化代码:不需要显式地定义迭代器或索引变量。
  • 安全性:自动处理容器的边界,减少越界错误。

示例代码

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    for(int i : vec) {
        std::cout << i << " ";
    }
    
    return 0;
}

 

高级用法

使用引用遍历并修改元素

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    for(int& i : vec) {
        i *= 2; // 每个元素乘以2
    }
    
    for(const int& i : vec) {
        std::cout << i << " ";
    }
    
    return 0;
}

3. 字符数组与频率统计

概述:字符数组用于存储字符的频率信息,通常用于字符串相关的算法中。

实现:使用大小为 26 的数组来记录每个小写字母的出现次数,数组索引对应字母的偏移量(例如 'a' 对应索引 0,'b' 对应索引 1)。

特点

  • 高效:使用数组进行频率统计和比较,时间复杂度为 O(1)。
  • 简单:数组索引和字符的偏移量直接对应,易于实现和理解。

示例代码

#include <iostream>
#include <string>

int main() {
    std::string s = "hello";
    int freq[26] = {0};
    
    for(char ch : s) {
        freq[ch - 'a']++;
    }
    
    for(int i = 0; i < 26; ++i) {
        if (freq[i] > 0) {
            std::cout << (char)('a' + i) << ": " << freq[i] << std::endl;
        }
    }
    
    return 0;
}

高级用法

判断两个字符串是否是字母异位词

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

bool isAnagram(std::string s1, std::string s2) {
    if (s1.size() != s2.size()) return false;
    
    int freq[26] = {0};
    
    for(char ch : s1) {
        freq[ch - 'a']++;
    }
    
    for(char ch : s2) {
        freq[ch - 'a']--;
    }
    
    for(int i = 0; i < 26; ++i) {
        if (freq[i] != 0) return false;
    }
    
    return true;
}

int main() {
    std::string s1 = "listen";
    std::string s2 = "silent";
    
    if (isAnagram(s1, s2)) {
        std::cout << s1 << " and " << s2 << " are anagrams." << std::endl;
    } else {
        std::cout << s1 << " and " << s2 << " are not anagrams." << std::endl;
    }
    
    return 0;
}

4. 双指针(Sliding Window)技巧

概述:双指针技术通常用于处理数组或字符串中的子数组或子串问题。

实现:使用两个指针(左指针和右指针)来维护一个窗口,该窗口在数组或字符串中滑动,以寻找满足特定条件的子数组或子串。

特点

  • 高效:通过调整指针位置来动态维护窗口,减少不必要的计算。
  • 灵活:可以用于解决多种问题,如最长子串、最短子串、子数组和等。

示例代码

#include <vector>
#include <iostream>

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5, 6};
    int left = 0, right = 0, sum = 0, target = 10;
    
    while(right < nums.size()) {
        sum += nums[right++];
        
        while(sum > target) {
            sum -= nums[left++];
        }
        
        if(sum == target) {
            std::cout << "Subarray found from index " << left << " to " << right - 1 << std::endl;
        }
    }
    
    return 0;
}

高级用法

找到所有和为给定值的子数组

 

#include <vector>
#include <iostream>

std::vector<std::pair<int, int>> findAllSubarrays(std::vector<int>& nums, int target) {
    std::vector<std::pair<int, int>> result;
    int left = 0, right = 0, sum = 0;
    
    while(right < nums.size()) {
        sum += nums[right++];
        
        while(sum > target) {
            sum -= nums[left++];
        }
        
        if(sum == target) {
            result.push_back({left, right - 1});
        }
    }
    
    return result;
}

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5, 6};
    int target = 10;
    
    std::vector<std::pair<int, int>> subarrays = findAllSubarrays(nums, target);
    
    for(auto& p : subarrays) {
        std::cout << "Subarray found from index " << p.first << " to " << p.second << std::endl;
    }
    
    return 0;
}

5. 成员函数与类

概述:类是 C++ 的基本面向对象编程(OOP)结构,用于封装数据和操作数据的方法。成员函数是类的函数,可以操作类的成员数据。

实现

  • 类定义:使用 class 关键字定义类,类中可以包含数据成员和成员函数。
  • 成员函数:在类的内部定义的方法,可以操作类的成员变量。
  • 访问控制:通过 public, protected, private 控制成员的访问权限。

特点

  • 封装性:将数据和操作封装在一起,提高代码的可维护性和可重用性。
  • 继承性:类可以通过继承复用已有代码。
  • 多态性:通过虚函数实现多态,提高代码的灵活性。

示例代码

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

class Solution {
public:
    std::vector<int> findAnagrams(std::string s, std::string p) {
        std::vector<int> ret;
        int hash1[26] = { 0 };
        for(auto ch : p) hash1[ch - 'a']++;
        int hash2[26] = { 0 };
        int m = p.size();
        for(int left = 0, right = 0, count = 0; right < s.size(); right++) {
            char in = s[right];
            if(++hash2[in - 'a'] <= hash1[in - 'a']) count++;
            if(right - left + 1 > m) {
                char out = s[left++];
                if(hash2[out - 'a']-- <= hash1[out - 'a']) count--;
            }
            if(count == m) ret.push_back(left);
        }
        return ret;
    }
};

int main() {
    Solution solution;
    std::string s = "cbaebabacd";
    std::string p = "abc";
    std::vector<int> result = solution.findAnagrams(s, p);
    for(int index : result) {
        std::cout << index << " ";
    }
    return 0;
}

 

高级用法

类的继承

 

#include <iostream>

class Base {
public:
    void show() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void show() {
        std::cout << "Derived class" << std::endl;
    }
};

int main() {
    Base* basePtr;
    Derived derived;
    basePtr = &derived;
    
    basePtr->show(); // 调用基类的 show 方法
    derived.show();  // 调用派生类的 show 方法
    
    return 0;
}

虚函数与多态

#include <iostream>

class Base {
public:
    virtual void show() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived class" << std::endl;
    }
};

int main() {
    Base* basePtr;
    Derived derived;
    basePtr = &derived;
    
    basePtr->show(); // 调用派生类的 show 方法,实现多态
    
    return 0;
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

传统CS网络的新生——基于2G网络的远程灌溉实现

概述&#xff1a;iphone 实现远程电话触发&#xff0c;实现灌溉绿植的一般方法 方法一&#xff1a; 远程电话触发&#xff0c;音频线左右声道会产生一个信号&#xff0c;可以在后端利用SR锁存器暂存信号&#xff0c;后级可以接相应的控制电路实现灌溉。 方法二&#xff1a; 同…

记录阮一峰grid教程笔记

前言 看了阮一峰的grid教程&#xff0c;做一个笔记&#xff0c;主要自己看&#xff0c;有理解错误的地方后续更正&#xff0c;有新的理解后续补充。教程链接如下&#xff1a; CSS Grid 网格布局教程 - 阮一峰的网络日志 grid主要分为容器属性和项目的属性&#xff0c;在行列布…

React 学习——Context机制层级组件通信

核心思路&#xff1a;&#xff08;适用于所有层级&#xff0c;不仅仅是爷孙 父子&#xff09; createContext方法创建一个上下文对象在顶层组件 通过Provider组件提供数据在底层组件&#xff0c;通过useContext钩子函数使用数据 import { createContext, useContext } from …

NSSRound#4 Team

[NSSRound#4 SWPU]1zweb 考察&#xff1a;phar的反序列化 1.打开环境&#xff0c;审计代码 1.非预期解 直接用file伪协议读取flag,或直接读取flag file:///flag /flag 2.正常解法 用读取文件读取index.php,upload.php的源码 index.php: <?php class LoveNss{publi…

Java面试八股之Spring DAO的作用

Spring DAO的作用 Spring DAO (Data Access Object) 是 Spring 框架的一个重要组成部分&#xff0c;它提供了一套用于简化数据访问操作的抽象层。Spring DAO 的核心目的是使开发人员能够更容易地处理数据访问相关的异常&#xff0c;并提供一致的异常处理机制&#xff0c;同时简…

翻译: 可视化深度学习神经网络一

这是一个随意书写的28*28像素、分辨率很低的数字 3 但你的大脑一看见就能轻松辨识出来 &#xff0c;我想要你好好欣赏这点 人脑能够毫无障碍地辨识是非常厉害的 我的意思是&#xff0c;这个、这个、还有这个&#xff0c;都能被识别为 3 即使前后图像的图形组成有很大差异 当你…

什么情况?我代码没了

前两天检视代码时&#xff0c;发现PR里面有两个提交的描述信息一模一样&#xff0c;于是我提出应该将这两个提交合并成一个&#xff0c;保持提交树的清晰。 1 先储存起来&#xff01; 而同事这时正在开发别的特性&#xff0c;工作区不是干净的&#xff0c;没法直接执行 git r…

c程序杂谈系列(职责链模式与if_else)

从处理器的角度来说&#xff0c;条件分支会导致指令流水线的中断&#xff0c;所以控制语句需要严格保存状态&#xff0c;因为处理器是很难直接进行逻辑判断的&#xff0c;有可能它会执行一段时间&#xff0c;发现出错后再返回&#xff0c;也有可能通过延时等手段完成控制流的正…

python生成二维码指向说明书

python生成二维码转向文档 python生成二维码指向说明书 import qrcode# 生成包含本地文档路径的二维码 def generate_qrcode(local_file_path):qr qrcode.QRCode(version1,error_correctionqrcode.constants.ERROR_CORRECT_L,box_size10,border4,)qr.add_data(local_file_pa…

为什么要做边界值测试?

边界值测试的理解 边界值测试&#xff08;Boundary Value Testing&#xff09;是一种常用的软件测试方法&#xff0c;它侧重于测试输入值的边缘或临界条件。这些边缘条件通常包括最小值、最大值以及接近这些最小值和最大值的值。边界值测试的基本思想是&#xff0c;许多软件错…

微信支付API列表

接入前准备 更新时间&#xff1a;2023.08.24 在正式接入微信支付App服务前&#xff0c;你需要进行以下准备步骤&#xff1a; 选择接入模式&#xff1a;普通商户或普通服务商申请参数&#xff1a;AppID、商户号App支付页面规范 #选择接入模式 商户需要判断自己公司注册区域…

SuperMap GIS基础产品FAQ集锦(20240729)

一、SuperMap iDesktopX 问题1&#xff1a;您好&#xff0c;想请教一下&#xff0c;白模可以调整颜色吗 11.2.0 【解决办法】 右键白模图层&#xff0c;制作单值专题图&#xff0c;即可调整白模颜色。 问题2&#xff1a;这边有份矢量数据&#xff0c;导入到桌面里面要放很大…

Node.js + Axios 上传附件到 Gitee 仓库指定 Release

在软件开发过程中&#xff0c;自动化发布流程是提升效率的关键环节之一。本文将介绍如何使用 Node.js 和 Axios 库来自动化地向 Gitee 仓库的最新版本中上传发布包。通过读取项目中的 package.json 文件&#xff0c;获取版本信息&#xff0c;并自动将构建好的包文件上传到 Gite…

我们的前端开发逆天了!1 小时搞定了新网站,还跟我说 “不要钱”

大家好&#xff0c;我是程序员鱼皮。前段时间我们上线了一个新软件 剪切助手 &#xff0c;并且针对该项目做了一个官网&#xff1a; 很多同学表示官网很好看&#xff0c;还好奇是怎么做的&#xff0c;其实这个网站的背后还有个有趣的小故事。。。 鱼皮&#xff1a;我们要做个官…

【gofar远为门锁】酒店智能门锁源码 对接收银CyberWinApp-SAAS本地化-未来之窗行业应用跨平台架构

通过写房卡按钮写房卡 一、查看门锁读卡器信息 二、玄武星辰查到对应名称 如何知道自己家门锁的app&#xff0c;使用未来之窗【玄武芯辰】查询 通过上面我看出叫做gofar 在【玄武芯辰】输入gofar&#xff0c;人工智能会提示app信息 三、设置门锁控制app 在上一步找到app&a…

web服务器配置-(apache+nginx)

⼀、web基本概念和常识 Web&#xff1a;为⽤户提供的⼀种在互联⽹上浏览信息的服务&#xff0c;Web 服务是动态的、可交互的、跨平台的和图形化的。 Web 服务为⽤户提供各种互联⽹服务&#xff0c;这些服务包括信息浏览服务&#xff0c;以及各种交互式服务&#xff0c;包括聊…

LinuxCentos中安装apache网站服务详细教程

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…

【Opencv】色彩空间 color space

import os import cv2 img cv2.imread(os.path.join(.,dog.jpg)) # 在opencv中使用imread,读取的图片每个像素都是bgr色彩&#xff0c;蓝色&#xff0c;绿色&#xff0c;红色 cv2.imshow(img,img) cv2.waitKey(0) # 颜色空间转化&#xff1a;BGR2RGB img_rgb cv2.cvtC…

爱快路由的dns强制客户端代理真是个强大的功能

大致情况是这样的&#xff1a;同事说在linux服务器/etc/resolv.conf上随便写个IP地址【不在线的】&#xff0c;dns地址也能解析&#xff0c;让我帮忙查查。 我看了下也感觉纳闷&#xff0c;试了下不光在服务器上&#xff0c;我本地的pc随便设置了个dns解析也是一样的。 通过wir…

【黄啊码】零代码动手创建ModelScope Agent

还没开始学习&#xff0c;先来回复一下&#xff0c;什么是Agent Agent包含的模块 好了&#xff0c;开始发放干货&#xff1a; 1、创建通义千问API (新注册用户有一定的限时免费额度) 2、登录阿里云账号&#xff0c;打开 DashScope管理控制台&#xff0c;开通 DashScope灵积模…