周赛153

5181. 公交站间的距离 显示英文描述

环形公交路线上有 n 个站,按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离,distance[i] 表示编号为 i 的车站和编号为 (i + 1) % n 的车站之间的距离。

环线上的公交车都可以按顺时针和逆时针的方向行驶。

返回乘客从出发点 start 到目的地 destination 之间的最短距离。

case1:

输入:distance = [1,2,3,4], start = 0, destination = 1
输出:1
解释:公交站 0 和 1 之间的距离是 1 或 9,最小值是 1。

提示:

  • 1 <= n <= 10^4
  • distance.length == n
  • 0 <= start, destination < n
  • 0 <= distance[i] <= 10^4
class Solution {
    public int distanceBetweenBusStops(int[] distance, int start, int destination) {
        int mindis = 0;
        int sum  = 0;
        if (start == destination) {
            return 0;
        }
        for (int i = 0;i < distance.length;i++) {
            sum += distance[i];
        }
        if (start > destination) {
            start = start^destination;
            destination = start^destination;
            start = start^destination;
        }
        for (int i = start;i < destination;i++) {
            mindis += distance[i];
        }
        if (sum > mindis*2) {
            return mindis;
        } else {
            return sum - mindis;
        }
    }
}
  • 全球第一的答案
class Solution {
  template <typename T>
  vector<T> dijkstra(int s,vector<vector<pair<int, T> > > & G){
    const T INF = numeric_limits<T>::max();
    using P = pair<T, int>;
    int n=G.size();
    vector<T> d(n,INF);
    vector<int> b(n,-1);
    priority_queue<P,vector<P>,greater<P> > q;
    d[s]=0;
    q.emplace(d[s],s);
    while(!q.empty()){
      P p=q.top();q.pop();
      int v=p.second;
      if(d[v]<p.first) continue;
      for(auto& e:G[v]){
        int u=e.first;
        T c=e.second;
        if(d[u]>d[v]+c){
          d[u]=d[v]+c;
          b[u]=v;
          q.emplace(d[u],u);
        }
      }
    }
    return d;
  }

  //INSERT ABOVE HERE
public:
  int distanceBetweenBusStops(vector<int>& distance, int start, int destination) {
    int n=distance.size();
    using P = pair<int, int>;
    vector< vector<P> > G(n);
    for(int i=0;i<n;i++){
      int j=(i+1)%n;
      G[i].emplace_back(j,distance[i]);
      G[j].emplace_back(i,distance[i]);
    }
    return dijkstra(start,G)[destination];
  }
};

// 国内第一
class Solution {
public:
  int distanceBetweenBusStops(vector<int>& distance, int start, int destination) {
    vector<int> P(1);
    partial_sum(distance.begin(), distance.end(), back_inserter(P));
    if (start > destination) swap(start, destination);
    int k = P[destination] - P[start];
    return min(P.back() - k, k);
  }
};

5183. 一周中的第几天 显示英文描述

给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。

输入为三个整数:day、month 和 year,分别表示日、月、年。

您返回的结果必须是这几个值中的一个 {“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”}。

示例 1:

输入:day = 31, month = 8, year = 2019
输出:"Saturday"

示例 2:

输入:day = 18, month = 7, year = 1999
输出:"Sunday"

示例 3:

输入:day = 15, month = 8, year = 1993
输出:"Sunday"
  • 提示:

    给出的日期一定是在 1971 到 2100 年之间的有效日期。

// 
im
class Solution {
public:
    string dayOfTheWeek(int day, int month, int y) {
     if (month < 3) {
         y--;
         month += 12;
     }
     int w = (y + y / 4 - y / 100 + y / 400 + (13 * month + 8) / 5 + day) % 7;
     return S[w];
    }
};

class Solution {
public:
    int m[2][13] = {
        {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
        {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    };
    bool is_leap(int y) {
        return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
    }
    string dayOfTheWeek(int day, int month, int year) {
        vector<string> A = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
        // 2019/9/8 Sunday
        // int C = year / 100, Y = year % 100;
        // int ret = (day + (26 * month - 2) / 10 - 2 * C + Y + Y / 4 + C / 4) % 7;
        // return A[ret];
        int ret = 4;
        // 天数累加
        for (int i = 1971; i < year; ++i) {
            int k = is_leap(i);
            for (int j = 1; j <= 12; ++j) ret += m[k][j];
        }
        int k = is_leap(year);
        for (int i = 1; i < month; ++i) {
            ret += m[k][i];b
        }
        ret += day;
        ret %= 7;
        return A[ret];
    }
};

class Solution {
public:
  bool isLeap(int y) {
    return y % 400 == 0 || (y % 100 != 0 && y % 4 == 0);
  }
  
  string dayOfTheWeek(int day, int month, int year) {
    vector<int> md = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    vector<string> ds = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    int tot = 3;
    for (int y = 1970; y < year; y++) {
      tot += isLeap(y)?366:365; 
    }
    for (int m = 1; m < month; m++) {
      if (isLeap(year) && m == 2) tot += 29;
      else tot += md[m];
    }
    tot += day;
    return ds[tot % 7];
  }
};

5182. 删除一次得到子数组最大和

给你一个整数数组,返回它的某个 非空 子数组(连续元素)在执行一次可选的删除操作后,所能得到的最大元素总和。

换句话说,你可以从原数组中选出一个子数组,并可以决定要不要从中删除一个元素(只能删一次哦),(删除后)子数组中至少应当有一个元素,然后该子数组(剩下)的元素总和是所有子数组之中最大的。

注意,删除一个元素后,子数组 不能为空。

请看示例:

示例 1:

输入:arr = [1,-2,0,3]
输出:4
解释:我们可以选出 [1, -2, 0, 3],然后删掉 -2,这样得到 [1, 0, 3],和最大。

示例 2:

输入:arr = [1,-2,-2,3]
输出:3
解释:我们直接选出 [3],这就是最大和。

示例 3:

输入:arr = [-1,-1,-1,-1]
输出:-1
解释:最后得到的子数组不能为空,所以我们不能选择 [-1] 并从中删去 -1 来得到 0。
     我们应该直接选择 [-1],或者选择 [-1, -1] 再从中删去一个 -1。
  • 提示:

  • 1 <= arr.length <= 10^5

  • -10^4 <= arr[i] <= 10^4

动态规划

我们定义f ( i ) 和 g ( i ),

  • 其中 f( i ) 表示不删除元素的情况下最大子数组和(区间为[0,i]),
  • g( i ) 代表删除元素的情况下的最大子数组和(区间为[0,i])。
f(i) = Math.max(f(i-1)+arr[i],arr[i]) //要么是当前元素累加之前的和,要么是重新从当前元素开始
g(i) = Math.max(g(i-1)+arr[i],f(i-1)) 
//要么是加上当前元素,也就是维持之前删除某个元素的情形,即g[i-1]+arr[i]
//要么是删除当前这个元素,那么区间[0, i-1]就是不删除元素的情况,即f(i-1)+0(注意是f不是g!!)

问题在于初始化:

f(0)= arr[0] //因为必须要有元素,不能为 0 个元素

g(0) = 什么呢?

  • 举个例子,假设我们要计算g(1):
g(1) = Math.max(g(0)+arr[1],f(0))//题目提到至少保留一个元素,所以必须要选f(0),即g(0)要足够小
// g(0) + arr[1] < arr[0]
// g(0) < arr[0] - arr[1]
// 因为 - 10^4 <= arr[i] <= 10^4,所以arr[0]-arr[1] >= -2 * 10^4,即g(0)取-20001即可

最后遍历一遍 f 数组和 g 数组找出最大值即可。

  • 具体代码如下:
class Solution {
    public int maximumSum(int[] arr) {
        int len = arr.length;
        int[] f = new int[len];
        int[] g = new int[len];
        f[0] = arr[0];
        g[0] = -200001;
        for(int i=1;i<len;i++){
            f[i] = Math.max(f[i-1]+arr[i],arr[i]);//其实就是f(i-1)是否<0
            g[i] = Math.max(g[i-1]+arr[i],f[i-1]);
        }
        int res = Integer.MIN_VALUE; 
        for(int i=0;i<len;i++){
            res = Math.max(res,Math.max(f[i],g[i]));
        }
        return res;
    }
}

作者:xiaoxinganlinganim
链接:https://leetcode-cn.com/problems/maximum-subarray-sum-with-one-deletion/solution/bi-jiao-tong-su-yi-dong-de-dp-by-xiaoxinganlingani/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
// class Main {
public:
  int maximumSum(vector<int>& arr) {
    int _max = *max_element(arr.begin(), arr.end());
    if (_max <= 0) return _max;
    int N = arr.size();
    int cur = 0;
    vector<int> L(N);
    for (int i = 0; i < arr.size(); i++) {
      cur += arr[i];
      if (cur < 0) cur = 0;
      L[i] = cur;
    }
    int _max2 = *max_element(L.begin(), L.end());
    cur = 0;
    vector<int> R(N);
    for (int i = arr.size() - 1; i >= 0; i--) {
      cur += arr[i];
      if (cur < 0) cur = 0;
      R[i] = cur;
    }
    int t = 0;
    for (int i = 0; i < arr.size(); i++) {
      int l = i - 1 >= 0? L[i - 1]: 0;
      int r = i + 1 <  arr.size()? R[i + 1]: 0;
      t = max(t, l+r);
    }
    return max(_max2, t);
  }
// };

5184. 使数组严格递增 显示英文描述

给你两个整数数组 arr1 和 arr2,返回使 arr1 严格递增所需要的最小「操作」数(可能为 0)。

每一步「操作」中,你可以分别从 arr1 和 arr2 中各选出一个索引,分别为 i 和 j,0 <= i < arr1.length 和 0 <= j < arr2.length,然后进行赋值运算 arr1[i] = arr2[j]。

如果无法让 arr1 严格递增,请返回 -1。

示例 1:

输入:arr1 = [1,5,3,6,7], arr2 = [1,3,2,4]
输出:1
解释:用 2 来替换 5,之后 arr1 = [1, 2, 3, 6, 7]。

示例 2:

输入:arr1 = [1,5,3,6,7], arr2 = [4,3,1]
输出:2
解释:用 3 来替换 5,然后用 4 来替换 3,得到 arr1 = [1, 3, 4, 6, 7]。

示例 3:

输入:arr1 = [1,5,3,6,7], arr2 = [1,6,3,3]
输出:-1
解释:无法使 arr1 严格递增。
  • 提示:

1 <= arr1.length, arr2.length <= 2000
0 <= arr1[i], arr2[i] <= 10^9

class Solution {
  template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
  template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


  template<typename V>
  V compress(V v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    return v;
  }
  template<typename T>
  map<T, int> dict(const vector<T> &v){
    map<T, int> res;
    for(int i=0;i<(int)v.size();i++)
      res[v[i]]=i;
    return res;
  }
  map<char, int> dict(const string &v){
    return dict(vector<char>(v.begin(),v.end()));
  }

  //INSERT ABOVE HERE
public:
  int makeArrayIncreasing(vector<int>& arr1, vector<int>& arr2) {
    vector<int> as=arr1,bs=arr2;
    bs=compress(bs);

    int n=as.size(),m=bs.size();

    // dp[m] is for as[i]
    vector<int> dp(m+1,1);
    dp[m]=0;

    for(int i=1;i<n;i++){
      const int INF = 1e9;
      vector<int> nx(m+1,INF);

      for(int j=0;j+1<m;j++)
        chmin(nx[j+1],dp[j]+1);

      for(int j=0;j<m;j++)
        if(bs[j]<as[i]) chmin(nx[m],dp[j]);

      for(int j=0;j<m;j++)
        if(as[i-1]<bs[j]) chmin(nx[j],dp[m]+1);

      if(as[i-1]<as[i]) chmin(nx[m],dp[m]);
        
      swap(dp,nx);
    }

    int ans=*min_element(dp.begin(),dp.end());
    if(ans>n) ans=-1;
    return ans;
  }
};


// 
class Solution {
public:
    int makeArrayIncreasing(vector<int>& arr1, vector<int>& arr2) {
        int n = arr1.size();
        std::vector<vector<int>> dp(n+1,vector<int>(n+1,INT_MAX));
        
        /*intial*/
        dp[0][0] = -1;
        sort(arr2.begin(),arr2.end());
        
        for(int i = 1; i <= n; ++i){
            for(int j = 0;j <= i; ++j){
                if(arr1[i-1] > dp[j][i-1]){
                    dp[j][i] = arr1[i-1];
                }
                
                if(j > 0){
                    auto it = upper_bound(arr2.begin(),arr2.end(),dp[j-1][i-1]);
                    if(it != arr2.end()){
                        dp[j][i] = min(dp[j][i],*it);
                    }
                }
                if( i == n && dp[j][i] != INT_MAX){
                    return j;
                }
            }
        }
        
        return -1;
    }
};

// 作者:mike-meng
// 链接:https://leetcode-cn.com/problems/make-array-strictly-increasing/solution/dp-on2-by-mike-meng/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
    public int makeArrayIncreasing(int[] arr1, int[] arr2) {
         //特殊情况处理
        if (arr1 == null || arr1.length == 0) return -1;
        // 只有一个元素
        if (arr1.length == 1) return 0;
        // 处理arr2,去重,排序
        TreeSet<Integer> ts = new TreeSet<>();
        if (arr2 != null) {
            for (int i = 0; i < arr2.length; i++) ts.add(arr2[i]);
        }
        // 局部解存储,初始化
        int[][] dp = new int[arr1.length + 1][arr1.length + 1];
        for (int i = 0; i < dp.length; i++) Arrays.fill(dp[i], Integer.MAX_VALUE);
        dp[0][0] = Integer.MIN_VALUE;
        
        // 算法
        for (int j = 1; j < dp.length; j++) {
            for (int i = 0; i <= j; i++) {
                if (arr1[j - 1] > dp[i][j - 1]) {
                    dp[i][j] = arr1[j - 1];
                }
                // TreeSet 方法 higher,查找第一个大于目标元素的元素
                if (i > 0 && ts.higher(dp[i - 1][j - 1]) != null) {
                    dp[i][j] = Math.min(dp[i][j], ts.higher(dp[i - 1][j - 1]));
                }
                // 返回结果,最小的交换次数
                if (j == dp.length - 1 && dp[i][j] != Integer.MAX_VALUE) return i; 
            } 
        }
        return -1;
    }
}
// 作者:mike-meng
// 链接:https://leetcode-cn.com/problems/make-array-strictly-increasing/solution/dp-on2-by-mike-meng/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

💰

Title:周赛153

Count:3k

Author:攀登

Created At:2020-07-26, 00:19:44

Updated At:2024-06-15, 15:52:32

Url:http://jiafeimao-gjf.github.io/2020/07/26/%E5%91%A8%E8%B5%9B153/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

×

Help us with donation