【解题报告】力扣 第 73 场双周赛

一、数组中紧跟 key 之后出现最频繁的数字

1、算法:哈希表

  对于所有的key,把它下一个数哈希计数,然后统计所有哈希出来的最大的那个数。

2、源码

int mostFrequent(int* nums, int numsSize, int key){
    int hash[1001];
    int i, max;
    memset(hash, 0, sizeof(hash));
    for(i = 0; i <= numsSize - 2; ++i) {
        if(nums[i] == key) {
            ++hash[ nums[i+1] ];
        }
    }
    hash[0] = -1;
    max = 0;
    for(i = 1; i <= 1000; ++i) {
        if(hash[i] > hash[max]) {
            max = i;
        }
    }
    return max;
}

二、将杂乱无章的数字排序

1、算法:多关键字排序

  相当于两个关键字的排序,一个是映射后的值,一个是数组下标,模拟处理完,比较函数写好,做一次排序就行了。

2、源码


typedef struct {
    int val;
    int mapval;
    int input;
}Ptr;

int cmp(const void *a, const void *b) {
    Ptr *pa = (Ptr *)a;
    Ptr *pb = (Ptr *)b;
    if(pa->mapval == pb->mapval) {
        return pa->input - pb->input;
    }
    return pa->mapval - pb->mapval;
}

Ptr ptr[30005];

int* sortJumbled(int* mapping, int mappingSize, int* nums, int numsSize, int* returnSize){
    int stk[20], top;
    int n = numsSize;
    int i;
    int power;
    int *ret = (int *)malloc( sizeof(int) * n );
    for(i = 0; i < n; ++i) {
        top = 0;
        ptr[i].val = nums[i];
        ptr[i].mapval = nums[i] ? 0 : mapping[0];
        ptr[i].input = i;
        power = 1;
        while(nums[i]) {
            ptr[i].mapval += power * mapping[ nums[i] % 10 ];
            nums[i] /= 10;
            power *= 10; 
        }
    }
    qsort(ptr, n, sizeof(Ptr), cmp);
    for(i = 0; i < n; ++i) {
        ret[i] = ptr[i].val;
        //printf("%d ", ptr[i].mapval);
    }
    *returnSize = n;
    return ret;
}

三、有向无环图中一个节点的所有祖先

1、算法:深度优先搜索

  注意到总的边数不会超过 2000,所以 dist[i][j]表示i能否到j,对于每个 i,根据边进行一次深度优先搜索,总的时间复杂度只有 O ( n m ) O(nm) O(nm),然后再遍历dist[i][u]数组统计每个结点u能由哪些结点到达即可。

2、源码

class Solution {
    void dfs(int start, int u) {
        int i;
        if(dist[start][u] == 1) {
            return ;
        }
        dist[start][u] = 1;
        for(i = 0; i < e[u].size(); ++i) {
            dfs(start, e[u][i]);
        }
    }
    
public:
    vector<vector<int>> getAncestors(int n, vector<vector<int>>& edges) {
        vector<vector<int>> ans;
        int i, j;
        for(i = 0; i < n; ++i) {
            e[i].clear();    
        }
        for(i = 0; i < edges.size(); ++i) {
            int from = edges[i][0];
            int to = edges[i][1];
            e[ from ].push_back( to );
        }
        memset(dist, -1, sizeof(dist));
        
        priority_queue <int> q;
        for(i = 0; i < n; ++i) {
            dfs(i, i);
        }
        for(i = 0; i < n; ++i) {
            vector<int> ret;
            for(j = 0; j < n; ++j) {
                if(i != j && dist[j][i] == 1) {
                    ret.push_back(j);
                }
            }
            ans.push_back(ret);
        }
        
        return ans;
    }
private:
    vector <int> e[1010];
    int dist[1010][1010];
};

四、得到回文串的最少操作次数

1、算法:贪心

  先确定外层,再确定内层。
1)对于最左边的字符,在右边找一个最接近的,计算步数;
2)对于最右边的字符,在左边找一个最接近的,计算步数;
3)选择 1)和 2) 中的少的步数执行交换,然后再计算内层。

2、源码


int dfs(char *s, int l, int r) {
    int i, pos1, pos2, ans;
    if(l == r) {
        return 0;
    }
    if(l - 1 == r) {
        return 0;
    }
    for(i = r; i >= l; --i) {
        if(s[l] == s[i]) {
            pos1 = i;
            break;
        }
    }
    
    for(i = l; i <= r; ++i) {
        if(s[i] == s[r]) {
            pos2 = i;
            break;
        }
    }
    if(pos2 - l < r - pos1) {
        for(i = pos2; i > l; --i) {
            s[i] = s[i-1];
        }
        ans = pos2 - l;
    }else {
        for(i = pos1; i < r; ++i) {
            s[i] = s[i+1];
        }
        ans = r - pos1;
    }
    return ans + dfs(s, l+1, r-1);
    
}

int minMovesToMakePalindrome(char * s){
    int l = 0;
    int r = strlen(s) - 1;
    return dfs(s, l, r);
}
  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值