
6012. 统计各位数字之和为偶数的整数个数
思路 预处理
时间复杂度 查询 O ( 1 ) \mathrel{O}(1) O(1),预处理 O ( n ) \mathrel{O}(n) O(n)
空间复杂度 O ( n ) \mathrel{O}(n) O(n)
在查询之前预处理所有数字的答案,这样查询时即可 O ( 1 ) \mathrel{O}(1) O(1) 的得到答案。
借助 std::call_once 可使得预处理逻辑仅执行一次。
// cnt 存储答案
int cnt[1001] = {0};
// 预处理函数
void init() {
    for (int i = 1; i <= 1000; i++) {
        int sum = 0;
        for (int j = i; j; j /= 10) {
            sum += j % 10;
        }
        cnt[i] = cnt[i-1] + ((sum%2) ? 0 : 1);
    }
}
// std::call_once 函数所需的标记变量
std::once_flag flag;
class Solution {
public:
    int countEven(int num) {
        // 尝试调用预处理函数
        std::call_once(flag, init);
        // 返回答案
        return cnt[num];
    }
};
 
6013. 合并零之间的节点
思路 链表的基操啦
时间复杂度 O ( n ) \mathrel{O}(n) O(n)
空间复杂度 O ( 1 ) \mathrel{O}(1) O(1)
我觉得这道题主要在考察链表的遍历和删除。
设有 ListNode *cur 初始时指向头节点。使用 cur 从头至尾遍历链表。
设有 ListNode *zero 指向已遍历的节点中最靠后的零节点。初始时指向头节点。
按照上述变量的定义,在遍历过程中:
- 合并逻辑变为: 
zero->val += cur->val。 - 删除逻辑变为:每当 cur 指向一个零节点,则将 
zero->next = cur; zero = cur。即丢掉上一个零节点与当前零节点之间的节点,并更新zero。 
不难发现,遍历结束后,最后一个节点的值仍为零,需删除。
设有 ListNode *truncate 指向已遍历的节点中的倒数第二个零节点。初始时指向头结点。当遍历结束后,执行 tuncate->next = nullptr 即可解决上述问题。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeNodes(ListNode* head) {
        ListNode *truncate = head;
        for (ListNode *zero = head, *cur = head->next; cur != nullptr;cur = cur->next) {
            if (cur->val == 0) {
                // zero 要跳了。
                // 在跳之前,更新 truncate。
                // 这样 truncate 就指向了倒数第二个零节点。
                truncate = zero;
                
                // 删除节点
                zero->next = cur;
                // zero 跳到 cur
                zero = cur;
            } else {
                // 合并
                zero->val += cur->val;
            }
        }
        // 丢弃最后一个零节点
        truncate->next = nullptr;
        return head;
    }
};
 
6014. 构造限制重复的字符串
思路 贪心
时间复杂度 O ( n ∗ c ) \mathrel{O}(n*c) O(n∗c)。 n n n 为字符串长度, c c c 为字符种类数。
空间复杂度 O ( n + c ) \mathrel{O}(n+c) O(n+c)
设有字符串 a n w anw anw 存储答案,初始为空。
因为要是字典序最大,所以总是选择尽可能大的字符追加至 a n w anw anw 尾部。
一次选择字符的过程如下:
- 如果, s s s 中的最大字符与 a n w anw anw 尾部字符不同,或添加后不会超出重复限制,则将该字符从 s s s 删除,并追加至 a n w anw anw。
 - 否则,将一个次大字符从 s s s 中删除,并追加至 a n w anw anw。
 
最多重复 n n n 次挑选过程,即可构造出最大的 a n w anw anw。
class Solution {
public:
    string repeatLimitedString(string s, int repeatLimit) {
        // 统计每种字符出现的次数
        int cnt[26] = {0};
        for (auto c : s) {
            cnt[c-'a']++;
        }
        
        // anw 存储答案
        string anw;
        // rep anw尾部连续重复字符的个数
        int rep = 0; 
        // pre anw 尾部字符的编号,方便处理anw为空的情形。
        char pre = -1;
        // n 次挑选过程
        for (int op = 0; op < s.size(); op++) {
            // 从大的开始挑选
            for (int i = 25; i >= 0; i--) {
                // 检查第 i 种字符是否符合条件
                if (cnt[i] <= 0) continue;
                if (i == pre && rep >= repeatLimit) continue;
                
                // 更新数据
                anw += char(i+'a');
                if (i == pre) rep++;
                else rep = 1;
                pre = i;
                cnt[i]--;
                
                // 一次挑选过程只能挑一个字符
                break;
            }
        }
        return anw;
    }
};
 
6015. 统计可以被 K 整除的下标对数目
思路 最大公约数
时间复杂度 O ( n V ) \mathrel{O}(n\sqrt V) O(nV)
空间复杂度 O ( V ) \mathrel{O}(V) O(V)
如果三个正整数 x x x, y y y, k k k 满足 x ∗ y x*y x∗y 被 k k k 整除。
则 k k k 的所有质因子必然包含在 x ∗ y x*y x∗y 的质因子集合中。比如,
- k = 60 = 2 ∗ 2 ∗ 3 ∗ 5 k = 60 = 2*2*3*5 k=60=2∗2∗3∗5
 - x = 6 = 2 ∗ 3 x = 6 = 2*3 x=6=2∗3
 - y = 10 = 2 ∗ 5 y = 10 = 2*5 y=10=2∗5
 
显然 6 ∗ 10 6*10 6∗10 能被 60 60 60 整除。
根据上述结论,我们可枚举 
    
     
      
       
        n
       
       
        u
       
       
        m
       
       
        
         s
        
        
         i
        
       
      
      
       nums_i
      
     
    numsi,找出那些不在 
    
     
      
       
        n
       
       
        u
       
       
        m
       
       
        
         s
        
        
         i
        
       
      
      
       nums_i
      
     
    numsi 中的 
    
     
      
       
        k
       
      
      
       k
      
     
    k 的质因子,设这些质因子的乘积为 
    
     
      
       
        
         p
        
        
         i
        
       
      
      
       p_i
      
     
    pi,则有
 
     
      
       
        
         
          p
         
         
          i
         
        
        
         =
        
        
         
          k
         
         
          
           g
          
          
           c
          
          
           d
          
          
           (
          
          
           n
          
          
           u
          
          
           m
          
          
           
            s
           
           
            i
           
          
          
           ,
          
          
           k
          
          
           )
          
         
        
       
       
         p_i = \frac{k}{gcd(nums_i, k)} 
       
      
     pi=gcd(numsi,k)k
然后,统计出 
    
     
      
       
        n
       
       
        u
       
       
        m
       
       
        s
       
       
        [
       
       
        0..
       
       
        i
       
       
        −
       
       
        1
       
       
        ]
       
      
      
       nums[0..i-1]
      
     
    nums[0..i−1] 中有多少个数字被 
    
     
      
       
        
         p
        
        
         i
        
       
      
      
       p_i
      
     
    pi 整除,该数量记为 
    
     
      
       
        
         c
        
        
         i
        
       
      
      
       c_i
      
     
    ci。则答案为:
 
     
      
       
        
         a
        
        
         n
        
        
         w
        
        
         =
        
        
         
          ∑
         
         
          
           i
          
          
           =
          
          
           0
          
         
         
          
           n
          
          
           −
          
          
           1
          
         
        
        
         
          c
         
         
          i
         
        
       
       
         anw = \sum_{i=0}^{n-1}{c_i} 
       
      
     anw=i=0∑n−1ci
可以配合注释一起理解~
class Solution {
public:
    // cnt[i] 表示 nums 中能被 i 整除的数字的个数
    int cnt[100001] = {0};
    
    long long coutPairs(vector<int>& nums, int k) {
        // anw 记录答案
        int64_t anw = 0;
        // 开始枚举数字 nums[i]
        for(int i = 0; i < nums.size(); i++) {
            // 计算 p
            int p = k / __gcd(nums[i], k);
            // 累加上 nums[0..i-1] 区间内,能被 p 整除的数字的数量。
            anw += cnt[p];
            
            // 更新 cnt。将 nums[i] 统计进去,注意 nums[i] 能被多个数整除。
            for (int j = 1, s = sqrt(nums[i]); j <= s; j++) {
                if (nums[i]%j == 0) {
                    // j 能整除 nums[i],则 nums[i]/j 也能整除 nums[i]。
                    // 但须注意 j == nums[i]/j 的情形,避免重复统计。
                    cnt[j]++;
                    if (nums[i]/j != j) {
                        cnt[nums[i]/j]++;
                    }
                } 
            }
        }
        return anw;
    }
};










