6.19 note

最近的三数之和  16

排序➕双指针(优化一层循环)

class Solution {
public:
    int threeSumClosest(vector& nums, int target) {
        sort(nums.begin(),nums.end());
        //双指针优化一重循环
        int ans = nums[0] + nums[1] + nums[2];
        for(int i=0;i             int j = i+1,k=nums.size()-1;
            while(j                 int sum = nums[i] + nums[j] + nums[k];
                if(abs(target - sum) < abs(target - ans))

                ans = sum;
                if(sum > target) k--;
                else if(sum < target) j++;

                else return ans;
            }
        }
        return ans;
    }
};

喧闹和富有  DAG

6.19 note_第1张图片

 bfs 拓扑排序

  • - in[v] 表示v的入度(有多少人比v有钱,即v依赖多少人)。

class Solution {

    int n, G[501][501] = {0}, in[501] = {0};

    vector ans; 

public:

    vector loudAndRich(vector>& richer, vector& quiet)

{

        n = quiet.size();

        ans.resize(n);

        for(auto &r : richer)

         G[r[0]][r[1]] = 1, ++in[r[1]];//钱多 → 钱少

        

        queue q;

        for(int i = 0; i < n; ++i) ans[i] = i;

        for(int i = 0; i < n; ++i) if(!in[i]) q.push(i);

        while(!q.empty()){

            int u = q.front(); q.pop();           

            for(int v = 0; v < n; ++v) if(G[u][v]){

                if(quiet[ans[u]] < quiet[ans[v]]) ans[v] = ans[u];

                if(!--in[v]) q.push(v);

            }

        }

        return ans;

    }

};

 

dfs记忆化搜索

class Solution {//DFS 记忆化
    int n, G[501][501] = {0};
    vector ans;


    void dfs(int u, vector &quiet)

     {
        if(ans[u] != -1) return;    //memo
        ans[u] = u;
        for(int v = 0; v < n; ++v)

if(G[u][v])

{//如果存在比 u 更有钱的人 v
            dfs(v, quiet);

            if(quiet[ans[v]] < quiet[ans[u]])

                         ans[u] = ans[v];
        }
    }    


public:
    vector loudAndRich(vector>& richer, vector& quiet) {
        n = quiet.size();
        ans.resize(n, -1);
        for(auto &r : richer) G[r[1]][r[0]] = 1;

                       //钱少 → 钱多
        for(int i = 0; i < n; ++i) dfs(i, quiet);
        return ans;
    }
};
 

克隆图  lc113

hash+dfs

6.19 note_第2张图片

 class Solution {

public:

    unordered_maphash;

    Node* cloneGraph(Node* node) {

        if(!node) return NULL;

        return dfs(node);       

    }

    Node* dfs(Node* node)   

    {

        //node节点已经被访问过了,直接从哈希表hash中取出对应的克隆节点返回。

        if(hash[node]) return hash[node]; 

        Node* clone = new Node(node->val); //克隆节点

        hash[node] = clone; //建立源节点到克隆节点的映射

        for(Node* ver: node->neighbors) //克隆边

        {

            clone->neighbors.push_back(dfs(ver));

        }

        return clone;

    }

};

出入度  997

6.19 note_第3张图片

 class Solution {
public:
    int findJudge(int n, vector>& trust) {
  
        vector inDegree(n + 1, 0);   // 入度:被多少人信任
        vector outDegree(n + 1, 0);  // 出度:信任多少人
        
        for (auto& t : trust) {
            int a = t[0], b = t[1];
            outDegree[a]++;  // a信任b,a的出度+1
            inDegree[b]++;   // b被a信任,b的入度+1
        }
        
        // 遍历寻找法官:入度n-1且出度0
        for (int i = 1; i <= n; i++) {
            if (inDegree[i] == n - 1 && outDegree[i] == 0) {
                return i;
            }
        }
        return -1;
    }
};

cpp function函数包装器

C++函数包装器就像是一个“万能盒子”,能把各种可调用的东西(比如普通函数、类的成员函数、Lambda表达式)统一装起来,然后像调用普通函数一样用。

好处:

  • - 统一接口:不管原来的函数长啥样,包装后都能用相同方式调用,像“函数变形金刚”。
  • - 灵活存储:可以把函数存到容器里(比如 vector ),方便批量管理和使用。
  • - 延迟执行:先把函数“打包”,需要的时候再拿出来调用,适合异步任务或回调场景。
  • - 适配不同场景:比如STL算法需要函数参数时,包装器能让各种函数都满足要求。

简单说,它让函数使用更灵活,就像用一个通用遥控器控制不同电器。

图路径  1971

tip 两个true的场景

class Solution {
public:
    bool validPath(int n, vector>& edges, int source, int destination) 
    {
        vector> grip(n);
        for(auto& a:edges)
        {
            grip[a[0]].push_back(a[1]);
            grip[a[1]].push_back(a[0]);
        }
        vector vis(n);
       //防止死循环
       
        function dfs=
        [&](int i)->bool
        {
            if(i==destination)
                return true;

            
            vis[i]=true;
            for(auto& j:grip[i])
            {
                if(!vis[j] && dfs(j))
                    return true;

            }
            return false;
        };
        return dfs(source);
    }
};

 

并查集

class Solution {

public:

    bool validPath(int n, vector>& edges, int source, int destination) {

        vector p(n);

        iota(p.begin(), p.end(), 0);

        function find = [&](int x) -> int {

            if (p[x] != x) p[x] = find(p[x]);

            return p[x];

        };

        for (auto& e : edges) p[find(e[0])] = find(e[1]);      //构建并查集   下标里存的是终点

        return find(source) == find(destination);

    }

};

“并查集”判断两点是否连通,像在处理“朋友关系网”问题:

核心逻辑:

1. 初始化关系网:

-  vector p(n)  建一个长度为n的数组,存每个点的“老大”(初始时每个点自己当老大, iota 让p数组变成 [0,1,2,...,n-1] )。

2. 找老大函数(find):

- 递归找某个点的最终老大,同时“路径压缩”(让沿途点直接认老大,提高后续查找效率)。比如点A的老大是B,B的老大是C,就直接让A认C当老大。

3. 合并关系:

- 遍历所有边 edges ,把边两端的点所属集合合并(让它们的老大认同一个老大)。比如边连了点1和点2,就把1和2的老大合并成一伙。

4. 判断连通性:

- 最后看起点和终点的老大是否相同,相同则连通(在一个朋友圈里)。

通俗类比:

- n个点是n个人,edges是“朋友关系”,source和destination是要判断的两个人。

- 并查集就像给每个人找“社团老大”,朋友的朋友算同一社团。最后看两人是否同社团,同社团就有路径连通。

atoi   iota

atoi
 
作用:把字符串“翻译”成整数。
比如  "123"  用  atoi  处理后就是数字  123 ,遇到非数字字符会停止转换(如  "12a3"  转成  12 )。
 
iota
 
作用:给数组或容器“批量填数”,从某个值开始依次递增。
比如用  iota(arr, arr+3, 5) ,会让数组前3个元素变成  5,6,7 ,像自动按顺序贴标签。
 
总结:atoi 是“字符串→数字”转换器,iota 是“批量填递增数”的工具。

极大极小值  2239

模拟->原地模拟

6.19 note_第4张图片

 class Solution {

public:

    int minMaxGame(vector& nums) {

        for (int n = nums.size(); n != 1; n /= 2) {

            vector tem(n / 2);

            for (int i = 0; i < n / 2; i++)

tem[i] = i % 2? max(nums[2 * i], nums[2 * i + 1]) : min(nums[2 * i], nums[2 * i + 1]);

            nums = tem;    

        }

        return nums[0];

    }

};

原地模拟

class Solution {
public:
    int minMaxGame(vector& nums) {
        for (int n = nums.size(); n != 1; n /= 2)

{
            for (int i = 0; i < n / 2; i++)

nums[i] = i % 2? max(nums[2 * i], nums[2 * i + 1]) : min(nums[2 * i], nums[2 * i + 1]); 
        }
        return nums[0];
    }
};
 

递归模拟

class Solution {

public:

    int minMaxGame(vector& nums) {

        return fun(nums, nums.size());

    }

    int fun(vector& nums, int n) {

        if (n == 1) return nums[0];

        for (int i = 0; i < n / 2; i++) nums[i] = i % 2? max(nums[2 * i], nums[2 * i + 1]) : min(nums[2 * i], nums[2 * i + 1]); 

        return fun(nums, n / 2);

    }

};

图论简单bfs   lcp07

class Solution {
public:
    int numWays(int n, vector>& relation, int k) {
        vector> grip(n);  //邻接表
        for (auto& a : relation)
            grip[a[0]].push_back(a[1]);
         
        queue q;
        int ret = 0;
        
        
        if (k > 0) {  // 当k=0时无需移动
            for (auto& g : grip[0])
                q.push(g);
        }
        
        
        while (k > 0 && !q.empty()) {
            int sz = q.size();
            k--;
            
            while (sz--) {
                auto x = q.front();
                q.pop();
                
     if (k==0 && x == n - 1) ret++;  
                
                for (auto& next : grip[x])
                    q.push(next);
            }
        }
        return ret;
    }
};

 

你可能感兴趣的:(随记note,c++)