《剑指offer》第五章 39-52

Python 逆向解析知乎盐选反爬字体,实现内容精准还原 本文详细解析了知乎盐选内容的反爬字体机制,并提供了使用Python逆向解析WOFF字体文件的完整方案。通过fontTools库构建解码字典,实现乱码文本的精准还原,帮助开发者应对动态字体策略,同时强调法律与道德风险。 阅读详情

第五章 优化时间和空间效率

1. 时间效率

字符串多次拼接时,不要多次使用String的+来拼接字符串,这样会产生很多string临时实例。更好地是用append方法完成字符串拼接。s1.append(s2)把字符串s2拼接到s1后面。

查找:顺序查找需要O(n),排序数组需要O(logn),哈希表则是O(1)。

剑指 Offer 39. 数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

初始版本:将原数组排序,由于所求数超过数组长度地一半,所以中位数必为所求数。sort复杂度O(n)。可以利用快速排序或者快速选择替代sort。

   int majorityElement(vector<int>& nums) {
        int n = nums.size();
        if(n == 1) return nums.front();
        sort(nums.begin(),nums.end());
        return nums[n/2];
    }

优化:根据数组特点找出O(n)的算法。遍历数组的时候保存前一个遍历地数字和频次。当我们遍历到当前数字的时候,如果当前数字和我们之前保存的数字相同,则频次+1;如果当前数字和之前保存的数字不同,则频次+1。如果频次为零,我们需要保存当前数组,并把频次设为1。

由于我们要找的数字出现的频次比其他所有数字出现的频次之和还要多,那么要找的数字肯定是最后一次把频次设为1时对应的数字。

     int majorityElement(vector<int>& nums) {
         if(nums.size() == 1) return nums.front();
         int res = nums[0],times = 1;//遍历数组的时候保存遍历地数字和频次
         for(int i = 1;i < nums.size();++i){
             if(nums[i] == res) ++times;//如果当前数字和我们之前保存的数字相同,则频次+1
             else{
                 --times;//如果当前数字和之前保存的数字不同,则频次-1。
                 if(!times){
                     res = nums[i];times = 1;//如果频次为零,我们需要保存当前数字,并把频次设为1
                 }
             }
         }
         return res;
     }
剑指 Offer 40. 最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]

该算法适 合海量数据的输入。假设题目是要求从海量的数据中找出最小的k个数 字,由于内存的大小是有限的,有可能不能把这些海量的数据一次性全部载入内存。这个时候,我们可以从辅助存储空间(比如硬盘)中每次读入一个数字,因此它最适合的情形就是n很大并且k较小的问题。

    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        if(!k) return vector<int>{};
        if(arr.size() <= k) return arr;//如果数组内的元素个数小于k,直接全部输出
        priority_queue<int> pq;
        vector<int> res;
        for(int i = 0;i < k; ++i){//先将前k个放入大根堆中
            pq.push(arr[i]);
        }
        for(int i = k;i < arr.size();++i){//如果待插入的值比当前已有的最大值小,则用这个数替换当前最大值
            if(arr[i] < pq.top()){
                pq.pop();
                pq.push(arr[i]);
            }    
        }
        for(int i = 0;i < k; ++i){
            res.emplace_back(pq.top());
            pq.pop();
        }
        return res;
    }
剑指 Offer 41. 数据流中的中位数

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

例如,[2,3,4] 的中位数是 3。[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。

输入:
["MedianFinder","addNum","addNum","findMedian","addNum","findMedian"]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]

整个数据被中间一个或者两个数据分隔成两部分。左边的数据全部小于右边的数据。可以根据左边最大的数和右边最小的数得到中位数。所以将左边的数存入大根堆,右边的数存入小根堆。那么插入一个数的复杂度是O(logn),得到中位数复杂度是O(1)。

为了实现平均分配,当已有数据的总数目是偶数时,把新数据插入左边,也就是大根堆。当已有数据的总数目是奇数时,把新数据插入右边,即小根堆。插入过程中,如果新数据要插入左边,但新数据大于左边数据的最大值,那么把新数据插入右边,再把右边小根堆顶最小值删除,并插入左边。如果新数据要插入右边,但新数据小于右边数据的最小值,那么把新数据插入左边,再把左边大根堆顶最大值删除,并插入右边。

priority_queue<ListNode*,vector<ListNode*>,Comp>三个参数分别是<数据类型,保存数据的容器,元素比较方式>。

class MedianFinder {
private:
    priority_queue<int, vector<int>, less<int>> leftBig;//左边大根堆
    priority_queue<int, vector<int>, greater<int>> rightSmall;//右边小根堆
public:

    MedianFinder() {}
    
    void addNum(int num) {
        if(leftBig.size() == rightSmall.size()){//左右数量相等,则取出右边的一个对象push进入左边的大顶堆。
        //这里不是直接把num插入左边是为了防止新数据大于右边数据的最小值
           rightSmall.push(num);
           leftBig.push(rightSmall.top());
           rightSmall.pop();
        }else{//左边多一个,则取出左边的一个对象push进右边的小顶堆
            leftBig.push(num);
            rightSmall.push(leftBig.top());
            leftBig.pop();
        }
    }
    
    double findMedian() {
        double res = 0.0;
        if( leftBig.size() == rightSmall.size() ){//偶数
            res = ((double)leftBig.top() + (double)rightSmall.top() )/2.0;
        }else{
           res = leftBig.top();
        }
        return res;
    }
};
剑指 Offer 42. 连续子数组的最大和

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

当以第i-1个数字结尾的子数组中所有数字的和小于0时,如果把这个负数与第i个数累加,得到的结果比第i个数字本身还要小,所以这种情况下以第i个数字结尾的子数组就是第i个数字本身。

如果以第i-1个数字结尾的子数组中所有数字的和大于0,与第i个数字累加就得到以第i个数字结尾的子数组中所有数字的和。

    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        int cur = nums[0],res = cur;
        for(int i = 1;i < n;++i){
            if(cur < 0) cur = nums[i];
            else cur += nums[i];
            res = max(res,cur);
        }
        return res;
    }
剑指 Offer 43. 1~n 整数中 1 出现的次数

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

输入:n = 12
输出:5

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FGu2EIiO-1622635133201)(images/image-20210531001231487.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3CqoMY3F-1622635133203)(images/image-20210531001245084.png)]

    int countDigitOne(int n) {
        if(n < 1) return 0;
        long long digit = 1;//表示个位
        int high = n/10;//高位
        int cur = n%10;//当前位
        int low = 0;//低位,因为当前位是个位,所以低位为0
        int res = 0;
        
        while(high || cur){
            if(!cur) res += high*digit;
            else if(cur == 1) res += high*digit+low+1;
            else res += (high+1)*digit;

            low += cur*digit;//改变当前位以及前后位的数
            cur = high%10;
            high /= 10;
            digit *= 10;
        }
        return res;
    }
剑指 Offer 44. 数字序列中某一位的数字

数字以0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。请写一个函数,求任意第n位对应的数字。0 <= n < 231

输入:n = 11
输出:0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wR0Wl5xf-1622635133208)(images/image-20210531084745560.png)]

对于第 n 位对应的数字,我们令这个数字对应的数为 target,然后分三步进行。

  • 首先找到这个数字对应的数是几位数,用 digits 表示;

  • 然后确定这个对应的数的数值 target;

  • 最后确定返回值是 target 中的哪个数字。

    举个例子:

比如输入的 n 是 365:

经过第一步计算我们可以得到第 365 个数字表示的数是三位数,n = 365 - 9 - 90 = 176,digtis = 3。这时 n = 176 表示目标数字是三位数中的第 176 个数字。

我们设目标数字所在的数为 number,计算得到 number = 100 + 176/3 = 158,idx 是目标数字在 number 中的索引,如果 idx = 0,表示目标数字是 number 中的最后一个数字。

根据步骤2,我们可以计算得到 idx = n % digits = 176 % 3 = 2,说明目标数字应该是 number = 158 中的第二个数字,即输出为 5。

注意这道题n的范围0 <= n < 231,int能表示的范围是int的[ − 231 , 231 − 1 ],这道题很有可能超出int的范围,所以在编写程序过程中如果某个变量涉及到*操作时,尽量注意是否溢出。

    int findNthDigit(int n) {
        //计算该数字由几位数组成,由1位:digit = 1;2位:digit = 2...
        long long base = 9, digit = 1;
        while(n - base*digit > 0){//1~9有9个数,10~99有90个数,100~999有900个数,1000~9999有9000个数
            n -= base*digit;
            base *= 10;
            ++digit;
        }

        //计算真实代表的数字是多少
        int idx = n%digit;//由于上面的计算,n现在代表digit位数中的第n个数字
        if(!idx) idx = digit;
        long long number = 1;
        for(int i = 1;i < digit; ++i){
            number *= 10;
        }
        number += (idx == digit)? n/digit-1 : n/digit;

        //从真实的数字中找到我们想要的那个数字
        for(int i = idx; i < digit; ++i){
            number /= 10;
        }
        return number%10;
    }
剑指 Offer 45. 把数组排成最小的数

输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

输入: [3,30,34,5,9]
输出: "3033459"

首先解决大数问题,需要把数字转换成字符串,然后进行排序,可以使用内置的sort,也可以自己写快速排序。

  1. sort中的比较函数compare要声明为静态成员函数或全局函数,不能作为普通成员函数,否则会报错。 因为:非静态成员函数是依赖于具体对象的,而std::sort这类函数是全局的,因此无法再sort中调用非静态成员函数。**静态成员函数或者全局函数是不依赖于具体对象的, 可以独立访问,无须创建任何对象实例就可以访问。**同时静态成员函数不可以调用类的非静态成员。
  2. sort函数是比较是绝对大小,所以只能<或者>,不能>=或<=简单来讲函数如果比较两个相同的值,那么比较函数应该返回false,否则再运算过程中会产生冲突报错
class Solution {
public:
    string minNumber(vector<int>& nums) {
        vector<string> str;
        string res;
        for(auto &num:nums){
            str.push_back(to_string(num));
        }
        sort(str.begin(),str.end(),compare);
        for(auto & s:str){
            res.append(s);
        }
        return res;
    }
private:
    static bool compare(const string &a,const string &b){
        return a+b < b+a;//如比较30和3,显然303比330小,所以30应该在前边。比较3和34,显然334<343,所以3应该在前边,3<34
    }
};
  1. 自己写快速排序
class Solution{
public:
    string minNumber(vector<int> & nums){
        vector<string> strs;
        for(auto &num:nums){
            strs.push_back(to_string(num));
        }
        quickSort(strs, 0, strs.size()-1);//对字符串进行排序
        string res;
        for(auto & s:strs){
            res.append(s);
        }
        return res;
    }
    void quickSort(vector<string> & strs, int l, int r){
        if(l >= r) return;
        int i = l, j =r;
        while(i < j){
            while(strs[j] + strs[l] >= strs[l] + strs[j] && i < j) --j;//如果右边的数都大于基准strs[l],则继续
            while(strs[i] + strs[l] <= strs[l] + strs[i] && i < j) ++i;//如果左边的数都大于基准strs[l],则继续
            swap(strs[i],strs[j]);
        }
        swap(strs[i], strs[l]);
        quickSort(strs, l, i-1);
        quickSort(strs, i+1, r);
    }
};
剑指 Offer 46. 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"

按照一位数翻译还是按照两位数翻译,取决于前一个数字的大小。

如果前一个数为1,那么当前数无论是任何都可以;如果前一个数是2,当前数必须小于等于5,才有可能翻译成两位数。

除此之外,只能一个数一个数的翻译,那么翻译方式唯一等于前一个数字的翻译方式。

    int translateNum(int num) {
        string nums = to_string(num);
        int n = nums.size();
        if(n <= 1) return 1;
        int pre1 = 1, pre2 = 1,cur = 0;
        for(int i = 1;i < n; ++i){
            //如果前一个数为1,那么当前数无论是任何都可以;如果前一个数是2,当前数必须小于等于5,才有可能翻译成两位数
            if(nums[i-1] == '1' || (nums[i-1] == '2' && nums[i] <= '5') ){
                cur = pre1 + pre2;
            }else{
                cur = pre1;
            }
            pre2 = pre1;
            pre1 = cur;
        }
        return cur;
    }
剑指 Offer 47. 礼物的最大价值

在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

输入: [
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
/*    int maxValue(vector<vector<int>>& grid) {
        if(grid.empty()) return 0;
        int m = grid.size(),n = grid[0].size();
        vector<vector<int>> gift(m+1,vector<int>(n+1,0));
        for(int i = 1; i <= m; ++i){
            for(int j = 1; j <= n; ++j){
                gift[i][j] = max(gift[i-1][j], gift[i][j-1]) + grid[i-1][j-1];
            }
        }
        return gift[m][n];
    }
    */
    /*当前位置的礼物数,只与左边和上面的礼物数有关
    优化:利用一维数组代替上面位置礼物,利用left记录每次左边数量,从左往右遍历*/
    int maxValue(vector<vector<int>>& grid) {
        if(grid.empty()) return 0;
        int m = grid.size(),n = grid[0].size();
        vector<int> top(n,0);
        int left = 0,cur = 0;
        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                cur = max(left,top[j]) + grid[i][j];
                top[j] = cur;
                left = cur;
            }
            left = 0;//新的一行开始后,最左边礼物数为0
        }
        return cur;
    }
剑指 Offer 48. 最长不含重复字符的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

双指针:每次遍历固定左指针,移动右指针,将元素存入哈希表,如果右指针所指元素在哈希表种存在,则停止右指针,更新字串长度。下次一循环中,把字符串头部,也就是left所指元素删掉。

    int lengthOfLongestSubstring(string s) {
        if(s.size() <= 1) return s.size();//注意空格无法存入set中
        unordered_set<char> hash;
        int left = 0, right = left, res = 0;
        for(int left = 0; left < s.size(); ++left){
            if(left > 0) hash.erase(s[left-1]);//左指针向右移动一格,移除一个字符
            while(right < s.size() && !hash.count(s[right])){//如果不重复,不断移动右指针
                hash.insert(s[right]);
                ++right;
            }
            int len = hash.size();
            res = max(res,len);
        }
        return res;
    }

2.时间效率和空间效率的平衡

在软件开发的过程中我们允 许以牺牲一定的空间为代码来优化时间性能,以尽可能地缩短软件的响应时间。这就是我们通常所说的“以空间换时间”。

但对于一些嵌入式的开发就要慎重。

剑指 Offer 49. 丑数

我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。

基础版本:说如果一个数 能被2整除,我们把它连续除以2;如果能被3整除,就连续除以3;如 果能被5整除,就除以连续5。如果最后我们得到的是1,那么这个数就是丑数,否则不是。但每个整数都需要计算。即使一个数字不是丑数,我们还是需要对它做求余数和除法操作。

优化:根据丑数定义,丑数是另一个丑数乘以2、3、5的结果,所以可以创建一个数组,里面存储排序好的丑数,后面的每一个数字都是前面某个数乘2、3、5得到的。假设当前存在3个数组nums2,nums3,nums5分别代表从1开始分别乘以2,3,5的序列,则最终的丑数序列实际上就是这三个有序序列对的合并结果,计算丑数序列相当于合并三个有序序列。合并有序序列时,需要给每个序列都各自维护一个指针,然后比较指针指向的元素的值,将最小的元素放入有序丑数数组中,并将相应的指针向后移动一个元素。

    int nthUglyNumber(int n) {
        vector<int> dp(n); 
        dp[0] = 1;
        int p2 = 0, p3 = 0, p5 = 0;//2,3,5的倍数的序列指针
        for(int i = 1; i < n; ++i){
            dp[i] = min( min(dp[p2]*2, dp[p3]*3), dp[p5]*5);//从头开始,找到丑数序列中第i个数
            if(dp[i] == dp[p2]*2) ++p2;//找到当前丑数序列中第i个数对应的是三个倍数序列中的哪一个序列中的元素
            if(dp[i] == dp[p3]*3) ++p3;
            if(dp[i] == dp[p5]*5) ++p5;
        }
        return dp[n-1];
    }
剑指 Offer 50. 第一个只出现一次的字符

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

s = "abaccdeff"
返回 "b"
s = "" 
返回 " "
    char firstUniqChar(string s) {
        char res = ' ';
        if(s.empty()) return res;
        unordered_map<char,int> hash;
        for(auto &ss:s){
            hash[ss]++;
        }
        for(auto &h:hash){
            if(h.second == 1) res = h.first;
        }
        return res;
    }
剑指 Offer 51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

输入: [7,5,6,4]
输出: 5

利用归并排序的思想,本质是分而治之,每当调整两个数组中对应的两个数的顺序进行归并时都会进行一次数的比较,由于总是两个排序好的数组进行归并,所以每次归并的时候的逆序对都可以找出来,以此类推,直到归并所有的数。

    int reversePairs(vector<int>& nums) {
        vector<int> temp(nums.size());
        return mergeSort(0, nums.size()-1, nums, temp);
    }
    int mergeSort(int l, int r, vector<int> &nums, vector<int> &temp){
        if(l >= r) return 0;//终止条件
        int m = (l + r)/2;//递归划分
        int res = 0;
        res = mergeSort(l, m, nums, temp) + mergeSort(m + 1, r, nums, temp);
        //合并
        int i = l, j = m + 1;//i是左边一半数组的指针,j是右边一半数组的指针
        for(int k = l; k <= r; ++k){
            temp[k] = nums[k];//把l~r范围内的数拷贝进临时数组中
        }
        for(int k = l; k <= r; ++k){
            //i == m+1时,左边的数组遍历完了,只剩下右边的数组没有遍历完了,右边数组是已经排好序的状态,所以直接一次放进nums就行
            if(i == m+1) nums[k] = temp[j++];
            //j == r+1时,右边的数组遍历完了,只剩下左边的数组没有遍历完了,左边数组是已经排好序的状态,所以直接一次放进nums中
            else if(j == r+1 || temp[i] <= temp[j]) nums[k] = temp[i++];
            //另一种情况是左边数组中的当前元素要比右边数组中的当前元素小,那它就比右边元素剩下的当前元素小,所以不会在后序遍历中构成逆序对,所以直接放
            else{
                nums[k] = temp[j++];
                //前面已经包含了所有可能的情况,在else中就表示出现了一个逆序对,即左边数组的当前元素比右边数组中的大,所以左边数组中剩下的所有元素都比右边数组当前元素大
                res += m-i+1;//m=i+1等于当前左边数组中剩下的元素个数,因为剩下所有元素都比右边数组当前元素大,所以左边剩下多少个元素,当前就构成多少个逆序
            }
        }
        return res;
    }
剑指 Offer 52. 两个链表的第一个公共节点

输入两个链表,找出它们的第一个公共节点。

如下面的两个链表**:**

img

在节点 c1 开始相交。

    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(!headA || !headB) return nullptr;
        ListNode * A = headA, * B = headB;
        while(A != B){
            if( !A ) A = headB;
            else A = A->next;
            if( !B ) B = headA;
            else B = B->next;
        }
        return A;
    }
FPGA AXI DDR3读写时序调试与FIFO缓存实战解析 本文深入解析FPGA中AXI协议与DDR3的读写时序调试,重点探讨FIFO缓存在数据流控制中的关键作用。通过实战案例详细讲解突发传输中的地址对齐、数据分片等常见问题,并提供状态机设计、仿真波形分析和性能优化技巧,帮助开发者高效解决高速数据存储场景下的时序同步与数据一致性问题。 阅读详情

相关推荐

DSP配置I2C通讯(非IO口软件模拟时序)

dsp即数字信号处理器,是一种广泛应用的嵌入式处理器,主要应用是实时快速地实现各种数字信号处理算法,目前,国际主要的dsp供应商是ti公司,其tms32系列产品占据了dsp市场近一半的份额,本文以TMS320F28377D为例,使用ti公司dsp开发工具ccs10.1配置i2c模块。 写这篇文章的缘由,因为市面上很多DSP其实内部是具有硬件I2C接口的,但由于网络上大部分资料和例程都是利用IO口模拟I2C时序进而实现I2C通讯的。给很多想学习硬件I2C通讯的小伙伴带来了困难。 下面先介绍一下配置步骤 1.E

weixin_44387442的博客 5544

《剑指Offer》39. 数字在排序数组中出现的次数

题目:39. 数字在排序数组中出现的次数 知识点:二分查找 题目描述: 统计一个数字在排序数组中出现的次数。 解题思路: 解法一:先通过二分查找,确定连续的目标数字中的任意一个,然后通过循环来对其左右分别进行扫描,找到和目标数字相同的数字则次数加一,但这种解法的时间复杂度较高,为 O(n)。 解法二:这种解法的主要思想也是利用二分法来不断缩小区间来定位目标值的下标,只是这种解法定位的下...

Coder Yang 254

京瓷扫描驱动安装_京瓷喷头拆解和供墨原理剖析

在工业喷头打印领域,京瓷喷头作为主流喷头广泛应用于喷墨行业,目前京瓷喷头市面上销售主要有两个系列:KJ4A和KJ4B。其中KJ4A系列设计是用于油性墨水,例如UV墨水,主要用在广告领域;而KJ4B设计用于水性墨水,例如活性、分散墨水等,主要用在数码印花领域。最近我们团队对京瓷喷头进行了拆解分析,本期和大家分享一下我们对京瓷喷头拆解和喷头供墨原理的研究。京瓷喷头介绍1. KJ4A系列(油性)如下图所...

weixin_39883906的博客 1672

【剑指offer】剑指 Offer 39. 数组中出现次数超过一半的数字

剑指 Offer 39. 数组中出现次数超过一半的数字题目链接思路分析代码实现 题目链接 剑指 Offer 39. 数组中出现次数超过一半的数字 思路分析 1 第一种方法可以使用map结构来对出现的数字进行统计计数,然后遍历map寻找出现次数超过一半的数字就可以 2 为了方便理解,我们假设数据已经有序示例1中数据已经变成 1 2 2 2 2 2 3 4 5 可以看到2的个数是最多的,我们吧数据分为是2的和不是2的,可以相互进行抵消 如图所示,最终剩下的就是数组中出现次数超过一半的数字。 原数据是乱序的

qq_36711295的博客 179

大模型事件抽取学习——论文学习笔记《LLMs Learn Task Heuristics from Demonstrations:......》

本篇博客介绍一篇发表在2024 ACL main上的文章:《LLMs Learn Task Heuristics from Demonstrations: A Heuristic-Driven Prompting Strategy for Document-Level Event Argument Extraction》 方向:大模型事件抽取 本篇博客为个人阅读论文的总结与笔记,在这里进行简单的分享 论文链接:https://arxiv.org/abs/

weixin_53751318的博客 1850

AWS S3文件上传性能优化:Java SDK多线程与分段上传实战指南

本文详细介绍了如何通过Java SDK优化AWS S3文件上传性能,重点讲解多线程并发上传与分段上传(Multipart Upload)技术的实战应用。通过动态调整分段策略、线程池配置及内存优化技巧,可显著提升大文件上传效率,实测显示组合方案比单线程上传提速近5倍。文章还涵盖加密上传、断点续传等高级场景解决方案,并提供了完整的性能对比测试数据。

d6e7f8的博客 1016

《剑指offer》【剑指Offer 27.二叉树的镜像】

🏆个人主页:企鹅不叫的博客 ​ 🌈专栏 C语言初阶和进阶 C项目 Leetcode刷题 初阶数据结构与算法 C++初阶和进阶 《深入理解计算机操作系统》 《高质量C/C++编程》 ⭐️ 博主码云gitee链接:代码仓库地址 ⚡若有帮助可以【关注+点赞+收藏】,大家一起进步! 文章目录💎一、题目🏆1.题目描述🏆2.原题链接💎二、解题报告🏆1.思路分析🏆2.代码详解 💎一、题目 🏆1.题目描述 🏆2.原题链接 剑指Offer 27.二叉树的镜像 💎二、解题报告 🏆1.思路分析 🔑思路:.

YQ20210216的博客 218

Linux虚拟机mysql安装教程(详细步骤)出现了一个错误:依赖检测失败

Linux虚拟机安装mysql的详细步骤(有报错预警哦)

m0_74953387的博客 5255

剑指Offer系列之39:数组中出现次数超过一半的数(超简单思路分析)

剑指Offer系列之39:数组中出现次数超过一半的数(超简单思路分析) 一、题目详细描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 二、思路分析 1、首先题目假设数组非空,可以不考虑空数组情况,也可以在代码中加一句判别数组是否为空语句。 2、需要求的数字出现次数超过数组长度一半,说明它比其他所有数字的出现次数都多(至少多一次),因此可以考虑给

qq_43654303的博客 270

RAD Studio 12安装全攻略:从下载到破解InterBase的完整流程(附KeyPatch使用技巧)

本文提供RAD Studio 12的完整安装指南,包括系统要求、安装步骤及InterBase数据库的高效配置方法。详细介绍了如何使用KeyPatch工具进行许可证处理,并分享了IDE优化和开发技巧,帮助开发者快速上手这一强大的跨平台开发工具。

q6r7s8t9的博客 946

RK3568平台开发系列讲解(UBOOT篇)u-boot启动流程

U-Boot(Universal Bootloader)是一种开源的引导加载程序,广泛用于嵌入式系统中。它的主要功能是初始化硬件设备,加载操作系统内核,并将控制权交给操作系统。U-Boot的启动流程可以分为多个阶段,以下是典型的U-Boot启动流程:

内核笔记 1232

剑指offer39——数组中出现次数超过一半的数字(Python)

                         剑指offer39——数组中出现次数超过一半的数字(Python)   题目描述——网址,参考:大神解答        数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。   1、...

GeekZW的博客 4756

Mac电脑安装burp suite2024版本记录

下载最新版本burpsuitloader-XXX-all.jar,改名为burpsuitloader.jar。目录下,修改vmoptions.txt文件,新增以下内容,如果keygen不是这个名称的话,需要修改。,点击license左侧的copy复制它,然后手动从启动台启动burpsuite。,复制如下命令到终端即可(要加双引号,不然目录中空格会导致命令截断)再复制激活响应信息到burpsuite中即可激活。后续运行burp直接从启动台运行即可。将如下框的信息复制到激活器中。输入后下一步,点击手动激活。

墨痕诉清风的博客 899

【数据结构与算法】《剑指offer》学习笔记----第五章 优化时间和空间效率(含39-52题)

第五章 优化时间和空间效率 本章核心内容和思想,就是降低时间复杂度: (1)改用更加高效的算法。如39、40、42题 (2)用空间换时间。用数组实现简单哈希表在O(1)时间内知道任意字符出现的次数;创建一个缓存保存中间的计算结果避免重复计算;用递归思路求解问题的时候,如果有重复的子问题,也可以通过保存求解子问题的结果来避免重复计算。相关例题如10、49、50题 (3)嵌入式开发,不宜过度牺牲空间换时间。 以下是具体内容: 面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一

qq_30885821的博客 374

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【剑指offer】解题思路 39-52

文章目录第五章 优化时间和空间效率5.2 时间效率面试题39:数组中出现次数超过一半的数字面试题40:最小的k个数面试题41:数据流中的中位数面试题42:连续子数组的最大和面试题43:1~n整数中1出现的次数面试题44:数字序列中某一位的数字面试题45:把数组排成最小的数面试题46:把数字翻译成字符串面试题47:礼物的最大价值面试题48:最长不含重复字符的子字符串5.3 时间效率与空间效率的平衡面...

aaon22357的博客 297

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

剑指offer的python解答合集(更新完毕)

被疫情困在家里,没事刷刷剑指offer的题目,这里写一个题解合集,还没更完 20190129:搞定15道 文章目录面试题3:数组中重复的数字面试题4:二维数组中查找面试题5:替换空格面试题6:从尾到头打印链表面试题7:重建二叉树面试题8:二叉树的下一个节点面试题9:用两个栈实现队列面试题10:斐波那契数列面试题11:旋转数组的最小数字面试题12:矩阵中的路径面试题13:机器人的运动范围面试题14:...

yjyjjyjy1231的博客 944

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

剑指offer系列21:最小的K个数

从这个题开始,剑指offer进入了第五章,优化时间和时间效率。开始讲代码的优化,到这里就不得不说排序了。这个题可以用快排的思路做。只要看到这个题能联想到用快排做就解出一半了。 1 #include <iostream> 2 #include<vector> 3 using namespace std; 4 class Solution { 5 pub...

weixin_30497527的博客 76

剑指offer 第五章

面试题目 39 题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 思路 “数组中出现次数超过一半的数字” 简称为**“众数”**。需要注意的是,数学中众数的定义为 “数组中出现次数最多的数字” ,与本题定义不同。将众数的票数记为+1,非众数的票数记为-1,则所有元素的票数和

gbh18682030862的博客 174

【剑指offer】(第 2 版)Java 题解

【剑指offer】(第 2 版)Java 题解 第一章 面试的流程 略... 第二章 面试需要的基础知识 面试题 1. 赋值运算符函数 面试题 2. 实现 Singleton 模式 Solution 2 面试题 3. 数组中重复的数字 题目一:找出数组中重复的数字。 题目二:不修改数组找出重复的数字。 面试题 4. 二维数组中的查找 Solution 4 面试题 5. 替换空格 Solution ...

weixin_30873847的博客 206

剑指 Offer 题目分类全解析:75 道题 × 31 天刷题计划,LeetCode-Book 里的算法数据结构突击手册

晚上十点,你刚把 75 道剑指 Offer 题从题库里倒出来,第一反应不是激动,是慌:从哪道刷起?刷到一半发现树题全错,要不要停下计划回头补?这份基于 LeetCode-Book 仓库 `sword_for_offer` 模块整理的剑指 Offer 题目分类指南,就是为这种时刻准备的。它把 75 道题按「算法 × 数据结构」两个维度铺成一张地图,配上 31 天刷题计划和 Python/Java/C

gitblog_00510的博客 156

【剑指offer】解题思路汇总

文章目录第二章 面试需要的基础知识2.3 数据结构面试题3:数组中重复的数字题目一:找出数组中重复的数字题目二:不修改数组找出重复的数字面试题4:二维数组中的查找面试题5:替换空格相关题目:面试题6:从尾到头打印链表面试题7:重建二叉树面试题8:二叉树的下一个节点面试题9:用两个栈实现队列2.4 算法和数据操作面试题10:斐波那契数列面试题11:旋转数组的最小数字面试题12:矩阵中的路径面试题13...

aaon22357的博客 738

剑指offer——优化时间和空间效率(第五章)

面试题29:数组中出线次数超过一半的数字 数组中有一个数字出线的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。 思路1: 对于有序的数组,出线次数超过一半的数字肯定会出现在数组中间的位置。 对数组进行排列,然后直接输出排列后数组中间位置的数字 ...

weixin_33860528的博客 122

剑指offer(专项突破版):数据结构与算法名企面试题精讲 刷题记录

自己记录的刷题笔记

weixin_45883188的博客 1404

剑指offer:39-42记录

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 思路: 打擂台法: 擂主和打擂者不一样,就减一条命。擂主和打擂者一样,就加一条命。 擂主生命被减为0,就下台,由挑...

少说,多做。 6091

剑指offer-问题39

package offer; /** * offer interview 39 */ public class Test39 { private static class BinaryTreeNode{ int val; BinaryTreeNode left; BinaryTreeNode right; publ...

ma451152002的专栏 216

【剑指offer】39

KaelCui的博客 272
上一篇: 《剑指offer》第四章 27-38
下一篇: 黑马——C++基础入门
Netfishless
博客等级 码龄9年 3640粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值