【LeetCode】数组精选17题——双指针、滑动窗口、前缀和

目录

快慢指针:

1. 移动零(简单)

2. 复写零(简单)

对撞指针:

1. 两数之和 II - 输入有序数组(中等)

2. 三数之和(中等)

3. 有效三角形的个数(中等)

4. 四数之和(中等)

5. 盛最多水的容器(中等)

滑动窗口:

1. 长度最小的子数组(中等)

2. 将 x 减到 0 的最小操作数(中等)

3. 乘积小于 K 的子数组(中等)

4. 最大连续1的个数 III(中等)

5. 水果成篮(中等)

前缀和:

1. 寻找数组的中心下标(简单)

2. 和为 K 的子数组(中等)

3. 连续数组(中等)

4. 二维区域和检索 - 矩阵不可变(中等)

5. 矩阵区域和(中等)


双指针是一种常用的算法技巧,通常用于线性数据结构(数组、字符串、链表),使用两个指针扫描。指针并不是指C语言中的指针,而是指能定位数据结构中某个数据的手段,在数组中指的是下标。

双指针的形式:

  • 快慢指针:两个指针从一端向另一端移动,但移动速度不同
  • 对撞指针:两个指针从两端向中间移动,直到相遇或错开

滑动窗口是一种特殊的双指针,两个指针构造一个窗口,用于解决子数组的问题。右边界右移为进窗口,左边界右移为出窗口。

正数数组中子数组的和或积,就可以用滑动窗口解决。如果数组元素不全为正数,求子数组的和不能用滑动窗口,因为当数组中有负数时在子数组中添加数字不一定能增加数组之和,从子数组中删除数字也不一定能减少子数组之和。这时就需要用到前缀和思想。

快慢指针:

1. 移动零(简单)

数组分块问题,即根据一种划分方式,将数组分成两块,可以使用双指针解决。

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n = nums.size();
        int slow = -1; // 指向非0元素的最后一个
        int fast = 0;  // 指向待处理元素的第一个

        while (fast < n)
        {
            if (nums[fast] == 0) // fast扫描到0
            {
                fast++;
            }
            else // fast扫描到非0
            {
                swap(nums[++slow], nums[fast]);
                fast++;
            }
        }
    }
};

2. 复写零(简单)

如果从前往后原地复写0的话,会导致后面的元素被覆盖。例如,[2,0,5,1]    ->    [2,0,0,1]

所以本题采用从后往前复写0,首先要找到原数组从哪里截断。

当fast = n - 1时,说明数组给待处理元素剩的位置只有1个了,这个位置就是留给slow的,不管arr[slow]是0还是非0。将arr[slow]填到数组最后一个位置,然后从slow - 1开始从后往前复写。

当fast = n时,说明数组给待处理元素已经不剩位置了,并且fast一定是从n - 2位置走两步到n,所以上一步的slow一定指向0,然后写了2个0,到达数组末尾。将0填到数组最后一个和倒数第二个位置,然后从slow-2开始从后往前复写。

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int n = arr.size();
        int slow = 0;
        int fast = 0;
        // 找到截断点
        while (fast < n - 1)
        {
            // slow指向待处理元素的第一个
            // fast表示,如果发生复写,待处理元素的第一个的真正的位置
            if (arr[slow])
            {
                fast++;
            }
            else
            {
                fast +=2;
            }
            slow++;
        }
        // 判断fast,然后让slow指向待处理元素的第一个,fast表示待处理位置的第一个
        if (fast == n - 1)
        {
            arr[n - 1] = arr[slow];
            slow--;
            fast--;
        }
        else
        {
            arr[n - 1] = arr[n - 2] = 0;
            slow -= 2;
            fast -= 3;
        }
        // 从后往前复写
        while (slow >= 0)
        {
            if (arr[slow])
            {
                arr[fast] = arr[slow];
                fast--;
            }
            else
            {
                arr[fast] = arr[fast - 1] = 0;
                fast -= 2;
            }
            slow--;
        }
    }
};

对撞指针:

1. 两数之和 II - 输入有序数组(中等)

对撞指针的应用之一就是求排序数组的两个数字之和。如果和 < 目标值,左指针++,如果和 > 目标值,右指针--,直到和 == 目标值,就找到了那两个数。

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int n = numbers.size();
        int left = 0;
        int right = n - 1;
        while (left < right)
        {
            if (numbers[left] + numbers[right] < target)
            {
                left++;
            }
            else if (numbers[left] + numbers[right] > target)
            {
                right--;
            }
            else
            {
                return { ++left,++right }; // 因为下标从1开始
            }
        }
        return { -1,-1 };
    }
};

2. 三数之和(中等)

和两数之和类似,如果是排序数组,那么固定nums[i],用对撞指针从i的后面找nums[left] + nums[right] == -nums[i]。

答案不能有重复,所以要在找到一种答案后,跳过重复的元素。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        
        for (int i = 0; i < n - 2; )
        {
            int left = i + 1;
            int right = n - 1;
            while (left < right)
            {
                if (nums[left] + nums[right] < -nums[i])
                {
                    left++;
                }
                else if (nums[left] + nums[right] > -nums[i])
                {
                    right--;
                }
                else
                {
                    ans.push_back({ nums[i],nums[left++],nums[right--] });
                    // 去重left
                    while (left < right && nums[left] == nums[left - 1])
                    {
                        left++;
                    }
                    // 去重right
                    while (left < right && nums[right] == nums[right + 1])
                    {
                        right--;
                    }
                }
            }
            i++;
            // 去重i
            while (i < n - 2 && nums[i] == nums[i - 1])
            {
                i++;
            }
        }
        return ans;
    }
};

3. 有效三角形的个数(中等)

三角形的判定:任意两边之和大于第三边。

只要两条较短边>最长边,就可以推出任意两边之和大于第三边。

和三数之和类似,先给数组排序,固定最长边nums[i],用对撞指针从i的前面找nums[left] + nums[right] > nums[i]。

一旦向右移动left到某个位置时nums[left] + nums[right] > nums[i],就不需要再向右移动left了。因为只要保持right不动,[left, right)这个下标区间对应的任意一个元素,加上nums[right],都一定比nums[i]大。此时两个指针之间有多少个数字,就找到了多少组两条较短边>最长边。

答案可以有重复,不用跳过重复的元素。

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        int ans = 0;

        for (int i = n - 1; i >= 2; i--)
        {
            int left = 0;
            int right = i - 1;
            while (left < right)
            {
                if (nums[left] + nums[right] > nums[i])
                {
                    ans += right - left;
                    right--;
                }
                else
                {
                    left++;
                }
            }
        }
        return ans;
    }
};

4. 四数之和(中等)

先排序,固定一个数nums[a],再利用三数之和的解法找到三个数nums[b] nums[c] nums[d],使

nums[b] + nums[c] + nums[d] == target - nums[a]。

答案不能有重复,所以要在找到一种答案后,跳过重复的元素。

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        
        for (int i = 0; i < n - 3; ) // 固定nums[i]
        {
            for (int j = i + 1; j < n - 2; ) // 固定nums[j]
            {
                int sum1 = nums[i] + nums[j];
                int left = j + 1;
                int right = n - 1;
                while (left < right)
                {
                    int sum2 = nums[left] + nums[right];
                    if (sum2 < (long long)target - sum1)
                    {
                        left++;
                    }
                    else if (sum2 > (long long)target - sum1)
                    {
                        right--;
                    }
                    else
                    {
                        ans.push_back({ nums[i],nums[j],nums[left++],nums[right--] });
                        // 去重left
                        while (left < right && nums[left] == nums[left - 1])
                        {
                            left++;
                        }
                        // 去重right
                        while (left < right && nums[right] == nums[right + 1])
                        {
                            right--;
                        }
                    }
                }
                j++;
                // 去重j
                while (j < n - 2 && nums[j] == nums[j - 1])
                {
                    j++;
                }
            }
            i++;
            // 去重i
            while (i < n - 3 && nums[i] == nums[i - 1])
            {
                i++;
            }
        }
        return ans;
    }
};

5. 盛最多水的容器(中等)

假设左板的下标是left,右板的下标是right,两板与x轴构成的矩形的面积为:

S = (right - left) * min(height[left], height[right])

显然,矩形的面积由底边宽度和短板长度共同决定。

如果改变短板,向内收窄一格,底边宽度-1,短板的长度可能会变大,矩形的面积可能变大。

如果改变长板,向内收窄一格,底边宽度-1,由于短板决定高度,长板再怎么改变也没有用,矩形的面积一定变小。

class Solution {
public:
    int maxArea(vector<int>& height) {
        int n = height.size();
        int left = 0;
        int right = n - 1;
        int ans = 0;
        while (left < right)
        {
            ans = max(ans, ((right - left) * min(height[left], height[right])));
            if (height[left] < height[right])
            {
                left++;
            }
            else
            {
                right--;
            }
        }
        return ans;
    }
};

滑动窗口:

1. 长度最小的子数组(中等)

进窗口后判断子数组的和是否>= target,如果找到了和>= target的子数组,更新结果,然后出窗口,缩小子数组的长度,直到子数组的和 < target。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int left = 0;
        int right = 0;
        int sum = 0;
        int ans = INT_MAX;
        while (right < n)
        {
            // 进窗口
            sum += nums[right];
            // 判断子数组的和是否>=target
            while (sum >= target && left <= right)
            {
                // 更新结果
                ans = min(ans, right - left + 1);
                // 出窗口
                sum -= nums[left++];
            }
            // 更新右边界
            right++;
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

2. 将 x 减到 0 的最小操作数(中等)

问题可以理解成:求和为x的最左端子数组和最右端子数组的最小长度。

把问题转化成:求和为total - x的子数组的最大长度(total为数组所有元素的和)。

这道题nums[i]的取值范围是:1 <= nums[i] <= 104,求正数数组中子数组的和,显然用滑动窗口。

进窗口后判断子数组的和是否> total - x,如果已经> total - x了,要出窗口,减小子数组的和,直<= total - x。然后判断子数组的和到底是不是== total - x,如果找到了和== total - x的子数组,更新结果。

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int n = nums.size();
        int total = 0;
        for (auto& e : nums)
        {
            total += e;
        }

        int left = 0;
        int right = 0;
        int sum = 0;
        int ans = -1;
        while (right < n)
        {
            // 进窗口
            sum += nums[right];
            // 判断子数组的和是否>total-x
            while (sum > total - x && left <= right)
            {
                // 出窗口
                sum -= nums[left++];
            }
            // 找到和为total-x的子数组,更新结果
            if (sum == total - x)
            {
                ans = max(ans, right - left + 1);
            }
            // 更新右边界
            right++;
        }
        return ans == -1 ? ans : n - ans;
    }
};

3. 乘积小于 K 的子数组(中等)

进窗口后判断子数组的积是否>= k,如果已经 >= k了,要出窗口,减小子数组的积,直到< k。这时得到的子数组就是满足条件的子数组,并且,只要保持右边界不动,向右移动左边界形成的所有子数组的积就一定< k。此时左右边界之间有多少个元素,就找到了多少个乘积< k的子数组。

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        int n = nums.size();
        int left = 0;
        int right = 0;
        int prod = 1;
        int ans = 0;
        while (right < n)
        {
            // 进窗口
            prod *= nums[right];
            // 判断子数组的积是否>=k
            while (prod >= k && left <= right)
            {
                // 出窗口
                prod /= nums[left++];
            }
            // 更新结果
            ans +=  right - left + 1;
            // 更新右边界
            right++;
        }
        return ans;
    }
};

4. 最大连续1的个数 III(中等)

把问题转化成:求0的个数不超过k个的最长子数组。

用zero记录窗口中0的个数。进窗口的同时要维护zero,然后判断zero是否> k,如果已经> k了,要出窗口并维护zero,直到<= k。这时就找到了0的个数不超过k个的子数组,更新结果。

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n = nums.size();
        int left = 0;
        int right = 0;
        int zero = 0; // 窗口中0的个数
        int ans = 0;
        while (right < n)
        {
            // 进窗口+维护zero
            if (nums[right] == 0)
                zero++;
            // 判断zero是否>k
            while (zero > k && left <= right)
            {
                // 出窗口+维护zero
                if (nums[left] == 0)
                {
                    zero--;
                }
                left++;
            }
            // 更新结果
            ans = max(ans, right - left + 1);
            // 更新右边界
            right++;
        }
        return ans;
    }
};

5. 水果成篮(中等)

把问题转化成:求元素的种类只有2种的最长子数组。

用哈希表记录窗口中元素的种类和次数,key——元素的种类,value——每个元素出现的次数,哈希表的大小表示有多少种元素在窗口中。

进窗口后判断哈希表的大小是否> 2,如果已经> 2了,要出窗口,记得要把value为0的键值对删除,直到哈希表的大小== 2。这时就找到了元素的种类只有2种的子数组,更新结果。

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int n = fruits.size();
        int left = 0;
        int right = 0;
        unordered_map<int, int> hash; // key——元素的种类,value——每个元素出现的次数
        int ans = 0;
        while (right < n)
        {
            // 进窗口
            hash[fruits[right]]++;
            // 判断哈希表的大小是否>2
            while (hash.size() > 2 && left <= right)
            {
                // 出窗口
                hash[fruits[left]]--;
                if (hash[fruits[left]] == 0)
                {
                    hash.erase(fruits[left]);
                }
                left++;
            }
            // 更新结果
            ans = max(ans, right - left + 1);
            // 更新右边界
            right++;
        }
        return ans;
    }
};

前缀和:

1. 寻找数组的中心下标(简单)

如果sum - nums[i] == total - sum,i就是中心下标。

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int n = nums.size();
        int total = 0; // 所有元素的和
        for (auto& i : nums)
        {
            total += i;
        }
        int sum = 0; // 表示左子数组的和+nums[i]
        for (int i = 0; i < n; i++)
        {
            sum += nums[i];
            if (sum - nums[i] == total - sum)
                return i;
        }
        return -1;
    }
};

2. 和为 K 的子数组(中等)

每次累加新的前缀和,都往前找找有没有以前的前缀和 == 新的前缀和 - k。

用哈希表记录前缀和出现的次数,默认添加一个键值对(0, 1)。用sum表示当前位置的前缀和。

例如,nums = [3,2,1],k = 3,

将nums[0]添加进sum,sum = 3,sum - k = 0,恰好哈希表中存放了值为0的前缀和,出现的次数为1,将出现的次数添加进ans中,ans = 1。然后把当前位置的前缀和在哈希表中对应的值++,此时哈希表中有2个键值对:(0, 1), (3, 1)。

将nums[1]添加进sum,sum = 5,sum - k = 2,哈希表中没有存放值为2的前缀和,没找到满足条件的子数组,对ans不做处理。然后把当前位置的前缀和在哈希表中对应的值++,此时哈希表中有3个键值对:(0, 1), (3, 1), (5, 1)。

将nums[2]添加进sum,sum = 6,sum - k = 3,恰好哈希表中存放了值为3的前缀和,出现的次数为1,将出现的次数添加进ans中,ans = 2。然后把当前位置的前缀和在哈希表中对应的值++,此时哈希表中有4个键值对:(0, 1), (3, 1), (5, 1), (6, 1)。

循环结束,输出ans。

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {      
        int n = nums.size();
        unordered_map<int, int> hash; // key——前缀和 value——出现的次数
        hash[0] = 1; // 添加(0, 1)
        int sum = 0; // 当前位置的前缀和
        int ans = 0;
        for (auto& i : nums)
        {
            sum += i;
            if (hash.count(sum - k))
            {
                ans += hash[sum - k];
            }
            hash[sum]++;
        }
        return ans;
    }
};

3. 连续数组(中等)

把数组所有0替换成-1,题目转变为:找到和为0的最长连续子数组。

每次累加新的前缀和,都往前找找有没有以前的前缀和 == 新的前缀和。

用哈希表记录前缀和对应的最小下标(因为求最大子数组),默认添加一个键值对(0, -1)。用sum表示当前位置的前缀和。

例如,nums = [0,1,0],

将nums[0]添加进sum,如果是0,添加-1,如果是1,添加1,sum = -1,哈希表中没有存放值为-1的前缀和,没找到满足条件的子数组,对ans不做处理。然后把当前位置的前缀和及下标添加进哈希表中,此时哈希表中有2个键值对:(0, -1), (-1, 0)。

将nums[1]添加进sum,如果是0,添加-1,如果是1,添加1,sum = 0,恰好哈希表中存放了值为0的前缀和,下标为-1,所以子数组长度为1 - (-1) = 2,将它和ans比较,取最大的,ans = 2。

将nums[2]添加进sum,如果是0,添加-1,如果是1,添加1,sum = -1,恰好哈希表中存放了值为-1的前缀和,下标为0,所以子数组长度为2 - 0 = 2,将它和ans比较,取最大的,ans = 2。

循环结束,输出ans。

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        int n = nums.size();
        unordered_map<int, int> hash; // key——前缀和 value——最小下标
        hash[0] = -1; // 添加(0, -1)
        int sum = 0; // 当前位置的前缀和
        int ans = 0;
        for (int i = 0; i < n; i++)
        {
            sum += nums[i] == 0 ? -1 : 1;
            if (hash.count(sum))
            {
                ans = max(ans, i - hash[sum]);
            }
            else
            {
                hash[sum] = i;
            }
        }
        return ans;
    }
};

4. 二维区域和检索 - 矩阵不可变(中等)

创建一个和matrix一样大的二维前缀和数组sums,sums[i][j]记录matrix从(0,0)到(i,j)的子矩阵数字和。

(r1,c1)->(r2,c2)子矩阵数字和 =

sums[r2][c2] - sums[r2][c1 - 1] - sums[r1 - 1][c2] + sums[r1 - 1][c1 - 1]

如果r1或c1为0,r1 - 1或c1 - 1会越界。

为了防止越界,在sums的上面和左面分别加一行0和一列0,这样的话,sums[i+1][j+1]记录matrix从(0,0)到(i,j)的子矩阵数字和。

所以,(r1,c1)->(r2,c2)子矩阵数字和 =

sums[r2 + 1][c2 + 1] - sums[r2 + 1][c1] - sums[r1][c2 + 1] + sums[r1][c1]

class NumMatrix {
public:
    public:
    NumMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        sums.resize(m + 1, vector<int>(n + 1, 0)); // 上面和左面分别加一行0和一列0,防止越界
        // 处理前缀和数组
        for (int i = 0; i < m; i++)
        {
            int rowSum = 0;
            for (int j = 0; j < n; j++)
            {
                rowSum += matrix[i][j];
                sums[i + 1][j + 1] = sums[i][j + 1] + rowSum;
            }
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) {
        return sums[row2 + 1][col2 + 1] - sums[row2 + 1][col1] - sums[row1][col2 + 1] + sums[row1][col1];
    }

private:
    vector<vector<int>> sums; // sums[i+1][j+1]记录matrix从(0,0)到(i,j)的子矩阵数字和
};

5. 矩阵区域和(中等)

和上一题“二维矩阵区域和检索 - 矩阵不可变”类似。

注意矩阵左上角和右下角坐标的确定:

  • 左上角:r1 = max(0, i - k)          c1 = max(0, j - k)
  • 右下角:r2 = min(m - 1, i + k)    c2 = min(n - 1, j + k)
class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        int m = mat.size();
        int n = mat[0].size();

        // 处理前缀和矩阵
        vector<vector<int>> sums(m + 1, vector<int>(n + 1, 0)); // sums[i+1][j+1]记录matrix从(0,0)到(i,j)的子矩阵数字和
        for (int i = 0; i < m; i++)
        {
            int rowSum = 0;
            for (int j = 0; j < n; j++)
            {
                rowSum += mat[i][j];
                sums[i + 1][j + 1] = sums[i][j + 1] + rowSum;
            }
        }

        // 处理ans矩阵
        vector<vector<int>> ans(m, vector<int>(n));
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                int r1 = max(0, i - k);
                int c1 = max(0, j - k);
                int r2 = min(m - 1, i + k);
                int c2 = min(n - 1, j + k);
                ans[i][j] = sums[r2 + 1][c2 + 1] - sums[r2 + 1][c1] - sums[r1][c2 + 1] + sums[r1][c1];
            }
        }
        return ans;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python语言中“缩进”说法,python中的缩进规则

本篇文章给大家谈谈python语言中“缩进”说法&#xff0c;以及python中的缩进规则&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 缩进是Python的灵魂 Python是一门独特的语言&#xff0c;它的代码块是通过缩进&#xff08;Indentation&#xff09;来标记的&…

QT自带打包问题:无法定位程序输入点?metaobject@qsound

文章目录 无法定位程序输入点?metaobjectqsound……检查系统环境变量的配置&#xff1a;打包无须安装qt的文件 无法定位程序输入点?metaobjectqsound…… 在执行release打包程序后&#xff0c;相应的release文件夹下的exe文件&#xff0c;无法打开 如有错误欢迎指出 检查系…

LCR 181. 字符串中的单词反转

解题思路&#xff1a; class Solution {public String reverseMessage(String message) {message message.trim(); // 删除首尾空格int j message.length() - 1, i j;StringBuilder res new StringBuilder();while (i > 0) {while (i >…

如何批量获取CSDN文章数据并进行持久化

自己去看文章数据的话&#xff0c;比较慢&#xff0c;所以一直想通过程序来批量获取CSDN的文章数据&#xff0c;最近研究了一下&#xff0c;发现还是挺简单的&#xff0c;能够直接通过解析json来获取文章数据&#xff0c;跟大家分享一下。 文章目录 一、步骤1、首先我们到自己的…

JavaScript数组分组groupBy

JavaScript 最近发布了一个方法 Object.groupBy&#xff0c;可以对可迭代对象中的元素进行分组。 语法&#xff1a; Object.groupBy(items, callbackFn)items 被分组的可迭代对象&#xff0c;如 Array。 callbackFn 对可迭代对象中的每个元素执行的函数。 举个例子&#…

结构型设计模式(一):门面模式 组合模式

门面模式 Facade 1、什么是门面模式 门面模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;旨在为系统提供一个统一的接口&#xff0c;以便于访问子系统中的一群接口。它通过定义一个高层接口&#xff0c;简化了客户端与子系统之间的交互&#xf…

基于Java SSM框架实现图书店仓库进销存管理系统项目【项目源码+论文说明】

基于java的SSM框架实现图书店仓库进销存管理系统演示 摘要 仓库作为储存货物的核心功能之一&#xff0c;在整个仓储中具有非常重要的作用&#xff0c;是社会物质生产的必要条件。良好的仓库布局环境能够对货物进入下一个环节前的质量起保证作用&#xff0c;能够为货物进入市场…

FPGA设计与实战之时钟及时序简介1

文章目录 一、时钟定义二、基本时序三、总结一、时钟定义 我们目前设计的电路以同步时序电路为主,时钟做为电路工作的基准而显得非常重要。 简单的接口电路比如I2C、SPI等,复杂一点接口比如Ethernet的MII、GMII等接口,它们都有一个或多个时钟信号。 那么什么是时钟信号?它…

PADS9.5 : 原图绘图图纸尺寸下修改

原图绘图图纸尺寸下修改 图页边界线也要修改 如果二者选择不一致&#xff1a; 会出现下图所示情况&#xff1a;

Android hwcomposer服务启动流程

Android hwcomposer服务启动流程 客户端 binder远程调用 服务端 surfaceflinger --binder--> hwcomposer .hal文件编译时生成支持binder进程间远程调用通信的cpp文件 在out/soong/.intermediates/hardware/interfaces/graphics/composer/2.1/ 目录下找…

基于VGG-16+Android+Python的智能车辆驾驶行为分析—深度学习算法应用(含全部工程源码)+数据集+模型(三)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 模型构建3. 模型训练及保存1&#xff09;模型训练2&#xff09;模型保存 4. 模型生成1&#xff09;模型导入及调用2&#xff09;相关代码&#xff08;1&#xff09;布局文件&#xff08;2&#xff…

LCR 120. 寻找文件副本

解题思路&#xff1a; 利用增强for循环遍历documents&#xff0c;将遇见的id加入hmap中&#xff0c;如果id在hamp中存在&#xff0c;则直接返回id class Solution {public int findRepeatDocument(int[] documents) {Set<Integer> hmapnew HashSet<>();for(int d…

插入排序----希尔排序

希尔排序 希尔排序法又称缩小增量法。希尔排序法的基本思想是&#xff1a;先选定一个整数&#xff0c;把待排序文件中所有记录分成个gap组&#xff0c;所有距离为的记录分在同一组内&#xff0c;并对每一组内的记录进行排序。然后&#xff0c;取&#xff0c;重复上述分组和排序…

千亿露酒市场的未来之“露”

执笔 | 尼 奥 编辑 | 扬 灵 12月15日&#xff0c;以“以美为酿&#xff0c;品致未来”为主题的中国露酒产业发展大会暨露酒价值论坛在“中国酒都”宜宾举办。 近年来&#xff0c;露酒产业发展异军突起&#xff0c;市场销售规模超越黄酒、葡萄酒品类&#xff0c;成为中国酒…

【Qt QML 入门】TextEdit

TextEdit可以显示多行可编辑的格式化文。默认是无边框的&#xff0c;可以和父控件完美融合。 import QtQuick import QtQuick.Window import QtQuick.ControlsWindow {id: winwidth: 800height: 600visible: trueTextEdit {id: textEditanchors.centerIn: parenttext: "He…

Sentinel使用详解

组件简介 Sentinel是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。Sentinel承接了阿里巴巴近10年的双十一大促流量的核心场景&#xff0c;例如秒杀、消息削峰填谷、集群流量控…

翻译: LLM工具使用和代理Tool use and agents

欢迎来到本周的最后一个视频。在这个视频中&#xff0c;我想与您分享LLM&#xff08;大型语言模型&#xff09;开始能够使用工具的情况&#xff0c;以及讨论一下前沿的“代理”主题&#xff0c;这是让LLM自己决定下一步采取什么行动的领域。让我们来看看。在早期的食物订单接收…

操作系统期末复习-内存管理

一、内存管理 分页存储管理&#xff0c;是将一个进程的逻辑地址空间分成若干个大小相等的片&#xff0c;称为页面或页&#xff0c;并为各页加以编号&#xff0c;从0开始&#xff0c;如第0页、第1页等。相应地&#xff0c;也把内存空间分成与页面相同大小的若干个存储块&#xf…