Day 不知道是几|贪心算法part1

news2024/11/13 10:25:17

贪心算法

贪心算法一般分为如下四步:

将问题分解为若干个子问题 找出适合的贪心策略 求解每一个子问题的最优解 将局部最优解堆叠成全局最优解
这个四步其实过于理论化了,我们平时在做贪心类的题目 很难去按照这四步去思考,真是有点“鸡肋”。

做题的时候,只要想清楚 局部最优 是什么,如果推导出全局最优,其实就够了。

不好意思了,贪心没有套路,说白了就是常识性推导加上举反例。

好吧 开刷

455 分发饼干

思路不难但是注意读题啊。。。

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);

        int gCount = 0, sCount = 0;
        int gSize = g.length;
        int sSize = s.length;
        while (gSize > gCount && sSize > sCount) {
            if (g[gCount] > s[sCount]) {
                sCount++;
            } else if (g[gCount] <= s[sCount]) {
                sCount++;
                gCount++;    
            }
        }
        return gCount;
    }
}

注意java里对数组的排序和求值的方法
Arrays.sort();
s.length 数组没括号,list有括号length()

376 摆动序列

第一次没AC因为忽略了:
这种情况
这题也可以用动态规划来解 等我刷到动态规划的。。再回来
两种平坡情况

于是考虑只在diff波动的时候才更新preDiff(有点绕)

class Solution {
    public int wiggleMaxLength(int[] nums) {
        int result = 1;
        int preDiff = 0;
        int currDiff = 0;
        int n = nums.length;
        for(int i=0;i<n-1;++i){
            currDiff = nums[i+1]-nums[i];
            if(preDiff<=0 && currDiff >0){
                result++;
                preDiff = currDiff;
            }
            else if(preDiff >=0 && currDiff<0){
                result++;
                preDiff = currDiff;
            }
        }
        return result;
    }
}

https://programmercarl.com/0376.摆动序列.html#思路
参考

53. 最大子序和

暴力法当然可以解,时间复杂度不满足。
贪心思路:
局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。

class Solution {
    public int maxSubArray(int[] nums) {
        int curr = 0;
        int result = Integer.MIN_VALUE;
        int n = nums.length;
        for (int i = 0; i < n; ++i) {
            curr = curr + nums[i];
            result = curr > result ? curr : result;
            if (curr < 0) {
                curr = 0;
                continue;
            }
        }
        return result;
    }
}

注意java中最小量为Integer.MIN_VALUE
动态规划也可以解

122. 买卖股票的最佳时机 II

这道题算part2部分的了,但写都写了打算写个一发完的

因为可以多次买,贪心思路是把利润按天算入,当天买入第二天卖出,如果利润为正数就加到result中

class Solution {
    public int maxProfit(int[] prices) {
        int result = 0;
        int n = prices.length;
        for(int i = 1;i<n;++i){
            if(prices[i]-prices[i-1] > 0){
                result+=prices[i]-prices[i-1];
            }
        }
        return result;

    }
}

55. 跳跃游戏

感觉可以用回溯写一下:

class Solution {
    public boolean result = false;

    public boolean canJump(int[] nums) {
        backTrace(1,nums);
        return result;
    }

    public void backTrace(int curr, int[] nums) {
        int n = nums.length;
        if (result == true) {
            return;
        }
        if (curr >= n) {
            result = true;
            return;
        }
        // if(plus = 0){
        // return;
        // }
        int plus = nums[curr - 1];
        for (int i = 1; i <= plus; ++i) {
            curr += i;
            backTrace(curr, nums);
            curr -= i;
        }
        return;

    }
}

但是有用例超时了。。感觉我这已经算剪过枝的了
在这里插入图片描述

于是看看贪心:

贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。

这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。
注意这里更新覆盖范围,而不是更新每次跳到哪里,可以一步一步跳,在跳到最后一个格之前只要覆盖范围能达到,就可以直接返回true

class Solution {
    public boolean canJump(int[] nums) {
        int coverage = 0;
        int n = nums.length;
        if (n == 1) {
            return true;
        }
        for (int i = 0; i <= coverage; ++i) {
            coverage = Math.max(coverage, i + nums[i]);
            if (coverage >= n-1) {
                return true;
            }
        }
        return false;
    }
}

45.跳跃游戏 II (其实没太看懂)

感觉贪心算法可以是永远跳到coverage中最大的数上?
但每次跳完都要找到coverage中最大的数感觉时间复杂度有点高啊?

题解
从图中可以看出来,就是移动下标达到了当前覆盖的最远距离下标时,步数就要加一,来增加覆盖距离。最后的步数就是最少步数。

这里还是有个特殊情况需要考虑,当移动下标达到了当前覆盖的最远距离下标时

如果当前覆盖最远距离下标不是是集合终点,步数就加一,还需要继续走。
如果当前覆盖最远距离下标就是是集合终点,步数不用加一,因为不能再往后走了。

在这里插入图片描述
图中覆盖范围的意义在于,只要红色的区域,最多两步一定可以到!(不用管具体怎么跳,反正一定可以跳到)

核心思想:
i用来一步步模拟,ans才是实际走的步数

class Solution {
    public int jump(int[] nums) {
        int n = nums.length;

        int resultStep = 0;
        int currCoverage = 0;
        int nextCoverage = 0;
        for(int i= 0; i<n; ++i){//i其实是下一步要走的位置
            nextCoverage = Math.max(i + nums[i], nextCoverage);
            if(currCoverage >= n-1){
                break;
            }
            if(i == currCoverage){
                currCoverage = nextCoverage;
                resultStep++;
            }

        }
        return resultStep;
    }
}

1005.K次取反后最大化的数组和

没思路 看题解:

第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
第二步:从前向后遍历,遇到负数将其变为正数,同时K–
第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
第四步:求和

注意java比较器:

为什么是 Math.abs(o2) - Math.abs(o1) 而不是 Math.abs(o1) - Math.abs(o2)?
在 Java 中,Comparator 接口的 compare 方法需要返回一个整数,用于表示两个对象的比较结果:

如果返回负数,表示第一个对象小于第二个对象。
如果返回零,表示两个对象相等。
如果返回正数,表示第一个对象大于第二个对象。

而且这里是从大到小的排序,如果2大于1,那么应该排在前面。而sorted() // 默认从小到大排序,所以应该反着来,返回正数表示第一个对象大于第二个对象,那么第一个对象就会被排到后面(而我们比较器的逻辑是第二个对象的绝对值大,要排在前面)此时逻辑正好是通顺的(反着来的)

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        nums = IntStream.of(nums).boxed()
                .sorted((o1, o2) -> Math.abs(o2) - Math.abs(o1))
                .mapToInt(Integer::intValue).toArray();
        int n = nums.length;
        
        for (int i = 0; i < n; ++i) {
            if (k == 0) {
                break;
            }
            if (nums[i] < 0) {
                nums[i] = -nums[i];
                --k;
            }
        }

        if (k % 2 == 1)
            nums[n - 1] = -nums[n - 1];
        return Arrays.stream(nums).sum();
    }

}

顺便再写一下C++的比较器:
C++中的sort()正常也是从小到大排序
注意C++中sort的用法:要加begin和end
sort(A.begin(), A.end(), cmp);

C++中比较器要写成static

class Solution {
private:
    static bool cmp(int a, int b) {
        if (abs(a) > abs(b)) {
            return true;
        } else {
            return false;
        }
    }

public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end(), cmp);
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            if (nums[i] < 0) {
                nums[i] = -nums[i];
                --k;
            }
            if(k == 0){
                break;
            }
        }
        if (k % 2 != 0) {
            nums[n - 1] = -nums[n - 1];
        }
        int sum = 0;
        for (int a : nums) {
            sum += a;
        }
        return sum;
    }
};

134. 加油站

感觉暴力可解,但不知道怎么写贪心
看题解的贪心算法第二种(第一种感觉太怪了)

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int res = 0;
        int sum = 0;
        int start = 0;
        int n = gas.size();
        for (int i = 0; i < n; ++i) {
            sum += gas[i]-cost[i];
            res += gas[i]-cost[i];
        
            if(res < 0){
                start = i + 1;
                res = 0;
            }
        }
        if(sum < 0){
            return -1;
        }
        return start;
    }
};

JAVA这里也没什么坑 几乎是跟C++一样的写法

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int sum = 0;
        int res = 0;
        int n = gas.length;
        int start = 0;
        for(int i=0; i<n; ++i){
            res += gas[i] - cost[i];
            sum += gas[i] - cost[i];
            if(res < 0){
                res = 0;
                start = i+1;
            }
        }
        if(sum < 0){
            return -1;
        }
        return start;
    }
}

135 分发糖果

一开始想着更新i的时候同时更新i-1,后来举了反例 如果是递减的评分 那更新没完了 第一个小孩必须给最多,但一开始只能给一个,这就导致每次到新小孩的时候都要跑回去确认并更新前面小孩(直到第一个小孩的情况),这样肯定不行,时间复杂度太高了。

看题解,是一次只考虑左边小孩的,先是从前向后遍历一遍,再从后向前遍历一遍。。好聪明

class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int[] children = new int[n];
        int sum = 0;

        for (int i = 0; i < n; ++i) {
            if (i == 0) {
                children[i] = 1;
                continue;
            }
            if (ratings[i] > ratings[i - 1]) {
                children[i] = children[i - 1] + 1;
            } else {
                children[i] = 1;
            }

        }
        for (int i = n - 1; i >= 0; --i) {
            if (i == n - 1) {
                continue;
            }
            if (ratings[i] > ratings[i + 1]) {
                children[i] = Math.max(children[i + 1] + 1, children[i]);
            }
        }
        for (int a : children) {
            sum += a;
        }
        return sum;
    }
}

860.柠檬水找零

easy题很好想,纯枚举就好了,顺便用一个数组记录当前零钱数

class Solution {
    public boolean lemonadeChange(int[] bills) {
        int[] charges = new int[3];
        int n = bills.length;
        for(int i =0; i < n; ++i){
            if(bills[i] == 5){
                charges[0]++;
                continue;
            }else if(bills[i] == 10){
                if(charges[0] <= 0){
                    return false;
                }else{
                    charges[0]--;
                    charges[1]++;
                }
            }else{//20 可以转 10+5 可以找 三个5
                if(charges[0]>=1 && charges[1]>=1){
                    charges[2]++;
                    charges[0]--;
                    charges[1]--;
                }else if(charges[0] >= 3){
                    charges[0] -= 3;
                    charges[2]++;
                }else{
                    return false;
                }
            }
        }
        return true;
    }
}

贪心的点在于,优先消耗10元的钱,在收入20的时候判断能否找零,先判断charges[0]>=1 && charges[1]>=1这一情况

406.根据身高重建队列

看了一下题解发现,这道题的两个维度需要分开来考虑,一次排列中不能既考虑h又考虑k
所以可以像分糖果题一样排列两次?

先排列身高,从大到小,相同身高的就排列第二个量,第二个量小的放前面(稍微举个例子就能明白为啥)
然后按照排列好的顺序往一个新数组里插入,插入位置就是people[i][1]的值。
注意vector中insert函数的用法
.insert(people.begin() + position, value), 第一个参数表示插入后将要成为的位置,第二个参数表示想要插入的值

class Solution {
private:
    static bool cmp(vector<int> a, vector<int> b) {
        if (a[0] > b[0]) {
            return true;
        } else if (a[0] == b[0]) {
            if (a[1] > b[1]) {
                return false;
            } else {
                return true;
            }
        }
        return false;
    }

public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        int n = people.size();
        sort(people.begin(), people.end(), cmp); // 先按照身高从大到小排,
        vector<vector<int>> result;
        for (int i = 0; i < n; ++i) {
            int position = people[i][1];
            result.insert(result.begin() + position, people[i]);
        }
        return result;
    }
};

数组的insert操作是O(n),因此这个方法时间复杂度是O(n^2)

Java 使用链表(LinkedList)进行插入操作
Linkedlist.add(index, value),将value插入到指定index里

最后使用toArray(new int[n][])将链表插入
当然也可以直接指定行和列数que.toArray(new int [n][2]);

452. 用最少数量的箭引爆气球

看题解:
就是先给气球排序,按气球最左端或最右端排序(需要自己写比较器)
排序后按气球个数遍历(不是按坐标遍历)
遍历过程中改变原数组:如果当前气球和上一个气球有重叠,就把当前气球的最右端缩小掉min(当前右端,上一个右端),否则就加一支箭。

题解里有个思路可以学习一下就是在遍历的时候会改变当前数组的值更方便条件的判断(我一般不习惯改变数组的值,会习惯性默认它不可变,但有的时候改一下会更方便)

注意:
注意题目中说的是:满足 xstart ≤ x ≤ xend,则该气球会被引爆。那么说明两个气球挨在一起不重叠也可以一起射爆,(注意的是if条件的判断要带等号)

class Solution {
private:
    static bool cmp(vector<int> v1, vector<int> v2) {
        if (v1[0] > v2[0]) {
            return false;
        }
        return true;
    }

public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if (points.size() == 0) {
            return 0;
        }
        sort(points.begin(), points.end(), cmp);
        int result = 1;
        for (int i = 1; i < points.size(); ++i) {
            if(points[i][0] <= points[i-1][1]){
                points[i][1] = min(points[i][1], points[i-1][1]);
            }else{
                result++;
            }
        }
        return result;
    }
};

435. 无重叠区间

贪心的思路是有重合就移最长的?(想了一下确实找不到反例?
写比较器的时候,按区间左侧排序,如果相等,右侧更长的放右边。
注意比较器放在private,必须是static bool

这是因为:由于sort ()为全局函数,因此它的比较函数cmp ()只能是静态函数或全局函数。 如果想在类class内重构cmp (),cmp ()的成分为非静态成员函数,需要依附于对象.cmp ()使用,导致无法在sort ()中调用cmp ()
(写了有用例不通过,盘了一下发现逻辑上确实是有点小问题但不打算抠了,直接看题解)
但题解的贪心没有考虑到丢弃最长的数组
题解可以按左侧排序,也可以按右侧排序,我这里先看按左侧排序的

为什么用第一个比较器的时候(cmp1)有些用例会报错?

class Solution {
private:
    static bool cmp1(const vector<int>& a, const vector<int>& b){
        if(a[0] > b[0]){
            return false;
        }else if (a[0] == b[0]){
            if(a[1] > b[1]){
                return false;
            }
        }
        return true;
    }
    static bool cmp(const vector<int>& a, const vector<int>& b){
        return a[0] < b[0];
    }
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if(intervals.size() == 0){
            return 0;
        }
        sort(intervals.begin(), intervals.end(), cmp);
        int n = intervals.size();
        int result = 0;
        int end = intervals[0][1];
        for(int i = 1; i < n; ++i){
            if(intervals[i][0] < end){
                result++;
                end = min(end, intervals[i][1]);
            }else{
                end = intervals[i][1];
            }
        }
        return result;
    }
};

但是把第一个比较器加上等号就不会报错:
be like:

static bool cmp1(const vector<int>& a, const vector<int>& b){
        if(a[0] >= b[0]){
            return false;
        }else if (a[0] == b[0]){
            if(a[1] >= b[1]){
                return false;
            }
        }
        return true;
    }

问了豆包:
在这里插入图片描述
似乎是在自建比较器的时候等于的逻辑也需要判断为false

763. 划分字母区间

完全没思路的一道题:

看题解:

在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。

那么思路就是维护一个数组记录当前字符的最远距离,需要遍历两遍

vector如何初始化?
一维数组,
vector v = {1,2,3,4};直接赋值
vector v(n), 初始化n个为0的值
vector v(n,m), 初始化n个为m的值
vector v(v0);
使用另一个数组来初始化,v0也必须是vector

int a[5] = {1,2,3,4,5};
vector b = {7,8,9,10};
vector va(a+1, a+4);
vector vb(b.begin()+1,b.end()-1);

可以用其他数组指针初始化vector
以上va为2,3,4
vb为8,9

unordered_map用法:(感觉太久不写了,基本语法有点忘记。。这里稍微总结一下)

insert({}),
insert(pair<string, int>(“banana”, 3));
insert(make_pair(“orange”, 7));

使用emplace()函数直接构造键值对并插入
data.emplace(“pear”, 4);

erase():从容器中删除一个键值对。
clear(),清空容器
find():查找具有指定键的元素,并返回指向该元素的迭代器。如果没有找到,则返回指向 end() 的迭代器。
count():返回具有指定键的元素数量。

class Solution {
public:
    vector<int> partitionLabels(string s) {
        int n = s.size();

        vector<int> eachEnd;
        unordered_map<char, int> eachPosition;
        for (int i = 0; i < n; ++i) {
            auto it = eachPosition.find(s[i]);
            if (it == eachPosition.end()) {
                eachPosition.insert({s[i], i});
            } else {
                it->second = i;
            }
        }
        int each = 1;
        int maxEnd = 0;
        for (int i = 0; i < n; ++i) {
            maxEnd = max(maxEnd, eachPosition.find(s[i])->second);
            if (maxEnd == i) {
                eachEnd.push_back(each);
                each = 1;
            } else {
                each++;
            }
        }
        return eachEnd;
    }
};

注意这里,在第二次遍历的时候需要维护一个当前的最大边界的值,当i等于这个当前最大边界的值的时候就可以存了。

56. 合并区间

还是先排序(注意比较器的等号返回false)
需要维护一个新vector作为result返回
然后遍历,从1开始遍历,如果当前最左端大于新vector的最右端,pushback当前数组,else更新result中的当前数组的最右端到max(当前,result当前)。
按这个思路应该还比较好写的,时间复杂度O(nlogn),空间复杂度O(n)
时间复杂度

class Solution {
private:
    static bool cmp(vector<int> a, vector<int> b) { return a[0] < b[0]; }

public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(), cmp);
        vector<vector<int>> result;
        int n = intervals.size();
        result.push_back(intervals[0]);
        int curr = 0;
        for (int i = 1; i < n; ++i) {
            if (result[curr][1] < intervals[i][0]) {
                result.push_back(intervals[i]);
                ++curr;
            } else {
                result[curr][1] = max(result[curr][1], intervals[i][1]);
            }
        }
        return result;
    }
};

738. 单调递增的数字

看题解;
还可以使用string strNum = to_string(N);
直接把int转为string

有点抽象,首先可以明确从个位开始遍历,就是从后向前遍历,
然后贪心的思路是,给能赋值的地方都赋值为9,最终视为能取到的最大
从个位开始遍历的时候,需要记录从哪一位开始到个位都赋值9。
如果当前位置的前一位大于当前位置,那么就记录前一位-1,当前赋值9
局部最优视为全局最优
很难想的一种贪心.

最后还用了一种语法糖直接把string转换为int了
return stoi(strNum);
int stoi(const string& str, size_t* idx = 0, int base = 10);

其中:

  • str:要转换的字符串。

  • idx:可选参数,用于存储转换结束的位置即第一个无效字符的位置

  • base:可选参数,指定转换时使用的进制,默认为10进制。

class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        string result = to_string(n);
        int flag = result.size();

        for (int i = result.size() - 1; i > 0; --i) {
            if (result[i - 1] > result[i]) {
                flag = i;
                result[i - 1]--;
            }
        }
        for (int i = flag; i < result.size(); ++i) {
            result[i] = '9';
        }
        return stoi(result);
    }
};

968. 监控二叉树

后序遍历,需要从叶子节点开始遍历
枚举出每种节点的状态(共三种状态,有摄像头和没摄像头,没摄像头又可以分为有覆盖和无覆盖)
后序遍历递归地写,同时返回当前节点的状态
根据返回的左右节点状态判断当前节点应该处于啥状态
这里有个前提是空节点都返回有覆盖状态(不然叶子节点还需要加摄像头)
返回一共三种情况,
一种是左右节点都覆盖,此时当前节点应该作为被跳过的节点,不加摄像头,返回未覆盖的状态
第二种是左右节点存在没覆盖的,那当前节点一定返回加摄像头,同时计数
第三种是左右节点存在摄像头,那当前节点有覆盖。(注意第二种和第三种顺序,一定先筛掉子节点不存在无覆盖的情况再判断子节点是否有摄像头)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    int result = 0;
public:
    int minCameraCover(TreeNode* root) {
        if(traversal(root) == 0){
            return ++result;
        }
        return result;
    }
    int traversal(TreeNode* root){//0为无覆盖,1为有摄像头,2为有覆盖
        if(root == nullptr) return 2;
        int left = traversal(root->left);
        int right = traversal(root->right);
        if(left == 0 || right == 0){
            ++result;
            return 1;
        }else if(left == 2 && right == 2){
            return 0;
        }else if(left == 1 || right == 1){
            return 2;
        }
        return 0;
    }

};

贪心算法算是告一段落(暂时)

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

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

相关文章

c++中模版进阶和继承

类型参数非类型模版参数 //类型参数非类型模版参数 template<class T,int N> class Array { public:Array() {} private:T _a[N]; }; int main() {Array<int, 100> a1;return 0; } 注意&#xff1a; 1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。…

【兼容性记录】video标签在 IOS 和 安卓中的问题

业务需求背景&#xff1a;由于业务中涉及到有视频播放的内容&#xff0c;所以就使用了 video 标签去做&#xff0c;但是 video 标签在 ios 设备和安卓设备中的默认行为不一致&#xff0c;故记录下解决方法&#xff08;折中办法&#xff09;。 ios 自动全屏 ios 设备点击播放视频…

STC分散文件加载

一、什么是分散加载文件&#xff1f; 分散加载文件通常以.sct结尾&#xff0c;英文名是&#xff1a;Linker Control File, scatter loading&#xff0c;链接器根据这个文件的配置来分配各个节区的地址空间&#xff0c;并且生成分散加载代码&#xff0c;因此我们只要修改分散加载…

另一款插件开发中......

欢迎插眼&#xff01;&#xff01;&#xff01; 一款关于源码阅读和笔记记录的插件。发个图&#xff0c;还在开发中......Command Assist的难点是第一次接触IDEA插件&#xff0c;不管是项目工程结构&#xff0c;还是开发发布流程都比较陌生&#xff0c;然后是功能点里面的终端…

编码规范之注释、条件语句中限制代码行数和避免硬编码

对于软件开发管理来说&#xff0c;制订编码规范是一个历久弥新的话题。每一个大有为开发头目&#xff0c;都强调编码规范。或者程序员也互相攻讦&#xff08;jie&#xff0c;第二声&#xff0c;阳平&#xff09;&#xff0c;说你写的代码很乱&#xff0c;不规范&#xff0c;很难…

黑马JavaWeb开发笔记16——请求(postman、简单参数、实体参数、@RequestParam映射)

文章目录 前言一、postman工具1. 引入2. 介绍3. 安装4. 使用 二、简单参数1. 原始方式&#xff08;仅了解&#xff0c;以后的开发不会使用&#xff09;2. SpringBoot方式3. 参数名不一致(RequestParam映射) 三、实体参数1. 简单实体对象2. 复杂实体对象 总结 前言 本篇文章是2…

[CocosCreator]全栈接入微信支付宝SDK(V3)

原文再续,书接上一回!上一期我介绍了接入支付宝的SDK,本文就来讲讲微信的SDK接入.还是那句话,官方的文档,我只能用一句话形容:一言难尽!本屌还是一如既往,把"恶心的东西"嚼碎了喂给各位宝吃. 一.前言 首先还是要集齐可以召唤神龙的法器,给大家一一列举一下: 1.…

python学习第十节:爬虫基于requests库的方法

python学习第十节&#xff1a;爬虫基于requests库的方法 requests模块的作用&#xff1a; 发送http请求&#xff0c;获取响应数据&#xff0c;requests 库是一个原生的 HTTP 库&#xff0c;比 urllib 库更为容易使用。requests 库发送原生的 HTTP 1.1 请求&#xff0c;无需手动…

Notepad++插件:TextFX 去除重复行

目录 一、下载插件 TextFX Characters 二、去重实操 2.1 选中需要去重的文本 2.2 操作插件 2.3 结果展示 2.3.1 点击 Sort lines case sensitive (at column) 2.3.2 点击 Sort lines case insensitive (at column) 一、下载插件 TextFX Characters 点【插件】-【插件管理…

unity编辑器c#脚本

目录 1.编辑器窗口再介绍 1.1添加对象 1.2文件夹的管理 1.3参数的设置 1.4对象的移动方式 2.对于外形和材质的修改 2.1对于外形的修改 2.2对于材质的修改 3.添加有趣的组件 3.1如何添加组件 3.2添加刚体组件 3.3碰撞器的介绍 3.4添加c#组件 3.5c#脚本代码的说明 1…

通过知识蒸馏提升大模型训练效率

人工智能咨询培训老师叶梓 转载标明出处 随着模型规模的不断扩大&#xff0c;如GPT-4这样的模型拥有约1.7万亿参数&#xff0c;其预训练所需的巨大能源和计算资源引发了对可持续发展AI解决方案的迫切需求。麦吉尔大学的研究团队介绍了一种创新的方法来解决与LLMs预训练相关的效…

MySQL5.7基于mysqldump、xtrbackup、innobackupex工具进行全量备份/恢复、增量备份/恢复

mysql全量备份脚本 文章目录 前言一、数据库备份分类二、为什么需要备份&#xff1f;三、备份工具示例1.逻辑备份工具1.1.使用场景1.2.备份操作示例1.3.恢复操作示例 2.物理备份工具2.1.xtrbackup介绍2.2.使用场景2.3.安装percona-xtrabackup2.4.xtrbackup备份原理2.5.percona-…

西门子PLC读取时间相差8小时

当前时间与PLC读取到的时间相差8小时&#xff0c;如下图所示 原因&#xff1a;指令问题 模块时间总是存储在 CPU 时钟中&#xff0c;而不带因子“本地时区”或“夏令时”。之后&#xff0c;CPU 时钟将基于模块时间计算 CPU 时钟的本地时间。 解决办法&#xff1a;将读取时间指…

leetcode hot100_part01_哈希

1.两数之和 遍历数组&#xff0c;map中存在target - nums[i]就返回结果&#xff0c;不存在就把当前元素存入map; 49.字母异位词分组 分组&#xff0c;怎么分&#xff0c;用hashMap, key为每一组的标识&#xff0c;value为每一组包含的字符串&#xff08;属于同一组的&#xff…

【笔记】第一节. 引言

• 轨道用钢的加工过程 • 钢轨结构及其标准 • 轨道结构特点 • 钢轨的商业化及其发展趋势 轨道用钢的加工过程 钢轨形式及其标准 钢轨的基本结构 轨头、轨腰、轨底。 钢轨的技术标准 • 铁道行业标准《TB/T2344-2003&#xff1a;43&#xff5e;75 kg/m 热轧钢轨订货技术…

腾讯云Ubuntu系统安装宝塔,配置Java环境,运行spring boot项目

致谢 本次学习宝塔部署spring boot项目&#xff0c;参考如下资料 https://www.cnblogs.com/daen/p/15997872.html 系统安装宝塔 直接用的腾讯云云服务器面板上的登录&#xff0c;你可以换成 xshell 进入宝塔官网&#xff1a; https://www.bt.cn/new/download.html 我们采…

【Android】Handler用法及原理解析

文章目录 用处基本用法用法一&#xff1a;使用sendMessage和handleMessage方法用法二&#xff1a;使用post方法 法一工作原理Handler的sendMessageMessage成员变量 MessageQueueLooper主线程自动初始化子线程手动创建**prepare**loop Handler的dispatchMessage 法二工作原理Han…

机器学习中最常见的50个问题(进阶篇)

机器学习中最常见的50个问题 进阶篇 1.解释SVM的工作原理。 SVM&#xff0c;全称支持向量机&#xff08;Support Vector Machine&#xff09;&#xff0c;是一种有监督学习算法&#xff0c;主要用于解决数据挖掘或模式识别领域中的数据分类问题。 SVM的工作原理是建立一个最…

TypeScript 扩展

扩展 ?:可选参数 可选链事实上并不是TypeScript独有的特性&#xff0c;它是ES11&#xff08;ES2020&#xff09;中增加的特性 可选链使用可选链操作符 ? 作用是当对象的属性不存在时&#xff0c;会短路&#xff0c;直接返回undefined&#xff0c;如果存在&#xff0c;那么…

小程序开发设计-小程序简介①

1.小程序与普通网页开发的区别&#xff1a; 1.运行环境不同&#xff1a; 网页运行在浏览器环境中。 小程序运行在微信环境中。 2.API不同&#xff1a; 由于运行环境不同&#xff0c;所以小程序中&#xff0c;无法调用DOM和BOM的API。但是&#xff0c;小程序中可以调用微信环境提…