1029. 两地调度
公司计划面试
2N
人。第i
人飞往A
市的费用为costs[i][0]
,飞往B
市的费用为costs[i][1]
。返回将每个人都飞到某座城市的最低费用,要求每个城市都有
N
人抵达。
示例:
输入:[[10,20],[30,200],[400,50],[30,20]] 输出:110 解释: 第一个人去 A 市,费用为 10。 第二个人去 A 市,费用为 30。 第三个人去 B 市,费用为 50。 第四个人去 B 市,费用为 20。 最低总费用为 10 + 30 + 50 + 20 = 110,每个城市都有一半的人在面试。
提示:
1 <= costs.length <= 100
costs.length
为偶数1 <= costs[i][0], costs[i][1] <= 1000
思路1:
- 贪心
- 先算出一个人去A市和B市的一个差值的绝对值,然后按绝对值进行排序,要使最后的费用总值最小,那么你需要先从差值较大的人中选出费用较小的,若去A市(B市)的人数够了,那么剩下的都去B市(A市)不需要再理他们之间的差值,因为你之后即使被迫选了两地费用中较大的,所造成的结果也没有前面差值较大中选的较大的值所造成的费用大
AcCode:
class Solution { private static class Job implements Comparable
{ int freeA; int freeB; int gz; public Job(int freeA,int freeB) { this.freeA = freeA; this.freeB = freeB; this.gz = Math.abs(freeA-freeB); } @Override public int compareTo(Job o) { return gz-o.gz; } } public int twoCitySchedCost(int[][] costs) { int N = costs.length/2; Job[] jobs = new Job[costs.length]; for (int i = 0; i < costs.length; i++) { jobs[i] = new Job(costs[i][0], costs[i][1]); } Arrays.sort(jobs); int res = 0; int A = 0;//A地数量 int B = 0;//B地数量 for (int i = jobs.length-1; i >=0; i--) { if(B==N) { res+=jobs[i].freeA; continue; }else if(A==N) { res+=jobs[i].freeB; continue; } if(jobs[i].freeA>jobs[i].freeB) { res+=jobs[i].freeB; B++; }else { res+=jobs[i].freeA; A++; } } return res; } } 思路2:
- dp
- 我们发现有i个人,若j个人去A地,那么就有(i-j)个人去B地
- i表示总共的人数,j表示去A地的人数
- 若j=0,那么代表没有人去A地,那么都只能去B地,所以dp[i][0] = dp[i-1][0]+costs[i-1][1](i>0)
- 设cost_a = costs[i-1][0],cost_b = costs[i-1][1],dp[i][j] = Math.min(dp[i-1][j-1]+cost_a,dp[i-1][j]+cost_b)
- 这里需要以下特判i==j时,该人只能去A地不能去B地,因为之前没有足够的人去A地
(dp图片来自花花酱,侵删)
AcCode:
class Solution { public int twoCitySchedCost(int[][] costs) { int n = costs.length; int[][] dp = new int[n+1][n+1]; //初始化 for (int i = 1; i < dp.length; i++) { dp[i][0] = dp[i-1][0]+costs[i-1][1]; } for (int i = 1; i < dp.length; i++) { for (int j = 1; j
1030. 距离顺序排列矩阵单元格
给出
R
行C
列的矩阵,其中的单元格的整数坐标为(r, c)
,满足0 <= r < R
且0 <= c < C
。另外,我们在该矩阵中给出了一个坐标为
(r0, c0)
的单元格。返回矩阵中的所有单元格的坐标,并按到
(r0, c0)
的距离从最小到最大的顺序排,其中,两单元格(r1, c1)
和(r2, c2)
之间的距离是曼哈顿距离,|r1 - r2| + |c1 - c2|
。(你可以按任何满足此条件的顺序返回答案。)
示例 1:
输入:R = 1, C = 2, r0 = 0, c0 = 0 输出:[[0,0],[0,1]] 解释:从 (r0, c0) 到其他单元格的距离为:[0,1]
示例 2:
输入:R = 2, C = 2, r0 = 0, c0 = 1 输出:[[0,1],[0,0],[1,1],[1,0]] 解释:从 (r0, c0) 到其他单元格的距离为:[0,1,1,2] [[0,1],[1,1],[0,0],[1,0]] 也会被视作正确答案。
示例 3:
输入:R = 2, C = 3, r0 = 1, c0 = 2 输出:[[1,2],[0,2],[1,1],[0,1],[1,0],[0,0]] 解释:从 (r0, c0) 到其他单元格的距离为:[0,1,1,2,2,3] 其他满足题目要求的答案也会被视为正确,例如 [[1,2],[1,1],[0,2],[1,0],[0,1],[0,0]]。
提示:
1 <= R <= 100
1 <= C <= 100
0 <= r0 < R
0 <= c0 < C
思路:
- 枚举每一个点,计算出每一个点与给定点之间的曼哈顿距离,之后排序就行
AcCode:
class Solution { private static class Point implements Comparable
{ int x; int y; int jl; public Point(int x,int y,int jl) { this.x = x; this.y = y; this.jl = jl; } @Override public int compareTo(Point o) { return jl-o.jl; } } public int[][] allCellsDistOrder(int R, int C, int r0, int c0) { int[][] res = new int[R*C][2]; Point[] points = new Point[R*C]; int index = 0; for (int i = 0; i < R; i++) { for (int j = 0; j < C; j++) { points[index++] = new Point(i, j, Math.abs(i-r0)+Math.abs(j-c0)); } } Arrays.sort(points); for (int i = 0; i < points.length; i++) { res[i][0] = points[i].x; res[i][1] = points[i].y; } return res; } }
1031. 两个非重叠子数组的最大和
给出非负整数数组
A
,返回两个非重叠(连续)子数组中元素的最大和,子数组的长度分别为L
和M
。(这里需要澄清的是,长为 L 的子数组可以出现在长为 M 的子数组之前或之后。)从形式上看,返回最大的
V
,而V = (A[i] + A[i+1] + ... + A[i+L-1]) + (A[j] + A[j+1] + ... + A[j+M-1])
并满足下列条件之一:
0 <= i < i + L - 1 < j < j + M - 1 < A.length
, 或0 <= j < j + M - 1 < i < i + L - 1 < A.length
.
示例 1:
输入:A = [0,6,5,2,2,5,1,9,4], L = 1, M = 2 输出:20 解释:子数组的一种选择中,[9] 长度为 1,[6,5] 长度为 2。
示例 2:
输入:A = [3,8,1,3,2,1,8,9,0], L = 3, M = 2 输出:29 解释:子数组的一种选择中,[3,8,1] 长度为 3,[8,9] 长度为 2。
示例 3:
输入:A = [2,1,5,6,0,9,5,0,3,8], L = 4, M = 3 输出:31 解释:子数组的一种选择中,[5,6,0,9] 长度为 4,[0,3,8] 长度为 3。
提示:
L >= 1
M >= 1
L + M <= A.length <= 1000
0 <= A[i] <= 1000
思路:
- 枚举由L构成的子数组,记录构成子数组的beginIndex,endIndex,Value,生成listL,同理枚举M构成的子数组生成listM
- 遍历listL和listM,若两个子数组不相交,那么计算两个子数组的和,从中取出最大值
AcCode:
class Solution { private static class Node{ int begin; int end; int value; public Node(int begin,int end,int value) { this.begin = begin; this.end = end; this.value = value; } } public int maxSumTwoNoOverlap(int[] A, int L, int M) { List
listL = new ArrayList (); int beginLValue = 0; for (int i = 0; i < L; i++) { beginLValue+=A[i]; } listL.add(new Node(0, L-1, beginLValue)); for (int i = L; i < A.length; i++) { beginLValue = beginLValue+A[i]-A[i-L]; listL.add(new Node(i-L+1, i, beginLValue)); } List listM = new ArrayList (); int beginMValue = 0; for (int i = 0; i < M; i++) { beginMValue+=A[i]; } listM.add(new Node(0, M-1, beginMValue)); for (int i = M; i < A.length; i++) { beginMValue = beginMValue+A[i]-A[i-M]; listM.add(new Node(i-M+1, i, beginMValue)); } int maxValue = 0; for (int i = 0; i < listL.size(); i++) { for (int j = 0; j < listM.size(); j++) { if(listL.get(i).end maxValue) { maxValue = k; } } } } return maxValue; } }
1032. 字符流
按下述要求实现
StreamChecker
类:
StreamChecker(words)
:构造函数,用给定的字词初始化数据结构。query(letter)
:如果存在某些k >= 1
,可以用查询的最后k
个字符(按从旧到新顺序,包括刚刚查询的字母)拼写出给定字词表中的某一字词时,返回true
。否则,返回false
。
示例:
StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // 初始化字典 streamChecker.query('a'); // 返回 false streamChecker.query('b'); // 返回 false streamChecker.query('c'); // 返回 false streamChecker.query('d'); // 返回 true,因为 'cd' 在字词表中 streamChecker.query('e'); // 返回 false streamChecker.query('f'); // 返回 true,因为 'f' 在字词表中 streamChecker.query('g'); // 返回 false streamChecker.query('h'); // 返回 false streamChecker.query('i'); // 返回 false streamChecker.query('j'); // 返回 false streamChecker.query('k'); // 返回 false streamChecker.query('l'); // 返回 true,因为 'kl' 在字词表中。
提示:
1 <= words.length <= 2000
1 <= words[i].length <= 2000
- 字词只包含小写英文字母。
- 待查项只包含小写英文字母。
- 待查项最多 40000 个。
思路:
- 将给定的单词逆序构成字典树,之后将query构成的单词逆序查找字典树有没有该单词就行
AcCode:
class StreamChecker { class TireNode{ int isEnd = 0; TireNode[] tireNodes = new TireNode[26]; public TireNode() { } } TireNode root = null;//字典树根结点 public void insert(String s) { TireNode p = root; for (int i = s.length()-1; i >0; i--) { char target = s.charAt(i); if(p.tireNodes[target-'a']==null) { p.tireNodes[target-'a'] = new TireNode(); } p = p.tireNodes[target-'a']; } char target = s.charAt(0); if(p.tireNodes[target-'a']==null) { p.tireNodes[target-'a'] = new TireNode(); } p.tireNodes[target-'a'].isEnd = 1; } public StreamChecker(String[] words) { root = new TireNode(); //建立一个字典树 for (int i = 0; i < words.length; i++) { insert(words[i]); } } StringBuilder builder = new StringBuilder(); public boolean query(char letter) { builder.append(letter); TireNode p = root; for (int i = builder.length()-1; i >=0; i--) { char target = builder.charAt(i); if(p.tireNodes[target-'a']==null) { return false; }else if(p.tireNodes[target-'a'].isEnd==1) { return true; } p = p.tireNodes[target-'a']; } return false; } }