LeetCode 824. 山羊拉丁文 / 396. 旋转函数 / 587. 安装栅栏(不会,经典凸包问题,学)
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 824. 山羊拉丁文 / 396. 旋转函数 / 587. 安装栅栏(不会,经典凸包问题,学)相关的知识,希望对你有一定的参考价值。
824. 山羊拉丁文
2022.4.21 每日一题
题目描述
给你一个由若干单词组成的句子 sentence ,单词间由空格分隔。每个单词仅由大写和小写英文字母组成。
请你将句子转换为 “山羊拉丁文(Goat Latin)”(一种类似于 猪拉丁文 - Pig Latin 的虚构语言)。山羊拉丁文的规则如下:
- 如果单词以元音开头(‘a’, ‘e’, ‘i’, ‘o’, ‘u’),在单词后添加"ma"。
例如,单词 “apple” 变为 “applema” 。 - 如果单词以辅音字母开头(即,非元音字母),移除第一个字符并将它放到末尾,之后再添加"ma"。
例如,单词 “goat” 变为 “oatgma” 。 - 根据单词在句子中的索引,在单词最后添加与索引相同数量的字母’a’,索引从 1 开始。
例如,在第一个单词后添加 “a” ,在第二个单词后添加 “aa” ,以此类推。
返回将 sentence 转换为山羊拉丁文后的句子。
示例 1:
输入:sentence = “I speak Goat Latin”
输出:“Imaa peaksmaaa oatGmaaaa atinLmaaaaa”
示例 2:
输入:sentence = “The quick brown fox jumped over the lazy dog”
输出:“heTmaa uickqmaaa rownbmaaaa oxfmaaaaa umpedjmaaaaaa overmaaaaaaa hetmaaaaaaaa azylmaaaaaaaaa ogdmaaaaaaaaaa”
提示:
1 <= sentence.length <= 150
sentence 由英文字母和空格组成
sentence 不含前导或尾随空格
sentence 中的所有单词由单个空格分隔
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/goat-latin
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
判断然后模拟就行了
class Solution
public String toGoatLatin(String sentence)
Set<Character> set = new HashSet<>();
set.add('a');
set.add('e');
set.add('i');
set.add('o');
set.add('u');
set.add('A');
set.add('E');
set.add('I');
set.add('O');
set.add('U');
String[] ss = sentence.split(" ");
for(int i = 0; i < ss.length; i++)
String s = ss[i];
if(set.contains(s.charAt(0)))
s = s + "ma";
for(int j = 1; j <= i + 1; j++)
s = s + "a";
ss[i] = s;
else
s = s.substring(1, s.length()) + s.charAt(0) + "ma";
for(int j = 1; j <= i + 1; j++)
s = s + "a";
ss[i] = s;
String res = "";
for(String s : ss)
res = res + s + " ";
return res.substring(0, res.length() - 1);
class Solution:
def toGoatLatin(self, sentence: str) -> str:
yuan = 'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U';
ss = sentence.split()
res = ''
for idx, word in enumerate(ss):
if word[0] not in yuan:
word = word[1:] + word[0]
word += 'ma' + (idx + 1) * 'a'
res += word + ' '
return res[0:-1]
396. 旋转函数
2022.4.22 每日一题
题目描述
给定一个长度为 n 的整数数组 nums 。
假设 arrk 是数组 nums 顺时针旋转 k 个位置后的数组,我们定义 nums 的 旋转函数 F 为:
F(k) = 0 * arrk[0] + 1 * arrk[1] + … + (n - 1) * arrk[n - 1]
返回 F(0), F(1), …, F(n-1)中的最大值 。
生成的测试用例让答案符合 32 位 整数。
示例 1:
输入: nums = [4,3,2,6]
输出: 26
解释:
F(0) = (0 * 4) + (1 * 3) + (2 * 2) + (3 * 6) = 0 + 3 + 4 + 18 = 25
F(1) = (0 * 6) + (1 * 4) + (2 * 3) + (3 * 2) = 0 + 4 + 6 + 6 = 16
F(2) = (0 * 2) + (1 * 6) + (2 * 4) + (3 * 3) = 0 + 6 + 8 + 9 = 23
F(3) = (0 * 3) + (1 * 2) + (2 * 6) + (3 * 4) = 0 + 2 + 12 + 12 = 26
所以 F(0), F(1), F(2), F(3) 中的最大值是 F(3) = 26 。
示例 2:
输入: nums = [100]
输出: 0
提示:
n == nums.length
1 <= n <= 10^5
-100 <= nums[i] <= 100
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-function
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
找规律
class Solution
public int maxRotateFunction(int[] nums)
//首先,因为数据范围很大,所以不能暴力
//那么自然而然就想到了能运用什么规律,然后再想相邻两个F之间有什么关系
//例如f(1) = f(0) + sum - nums[l-1] - (l-1)*nums[l - 1]
//总结一下 f(x) = f(x-1) + sum - l*nums[l - x]
int sum = 0;
for(int n : nums)
sum += n;
int l = nums.length;
int f0 = 0;
for(int i = 0; i < l; i++)
f0 += i * nums[i];
int max = f0;
for(int i = 1; i < l; i++)
f0 = f0 + sum - l * nums[l - i];
max = Math.max(max, f0);
return max;
class Solution:
def maxRotateFunction(self, nums: List[int]) -> int:
s = sum(nums)
f = sum(i * n for i, n in enumerate(nums))
res = f
l = len(nums)
for i in range(1, l):
f = f + s - l * nums[-i]
res = max(res, f)
return res
587. 安装栅栏
2022.4.23 每日一题
题目描述
在一个二维的花园中,有一些用 (x, y) 坐标表示的树。由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树。只有当所有的树都被绳子包围时,花园才能围好栅栏。你需要找到正好位于栅栏边界上的树的坐标。
示例 1:
输入: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]
输出: [[1,1],[2,0],[4,2],[3,3],[2,4]]
解释:
示例 2:
输入: [[1,2],[2,2],[4,2]]
输出: [[1,2],[2,2],[4,2]]
解释:
即使树都在一条直线上,你也需要先用绳子包围它们。
注意:
所有的树应当被围在一起。你不能剪断绳子来包围树或者把树分成一组以上。
输入的整数在 0 到 100 之间。
花园至少有一棵树。
所有树的坐标都是不同的。
输入的点没有顺序。输出顺序也没有要求。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/erect-the-fence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
真·不会做
想了半天,明白题的意思是找最外围的边界,但是怎么找不会
想到一个方法是先将最上下左右的点连接,形成一个图形,然后遍历其他点,如果点在图形内,那么不能添加,如果在图形外,可以添加
然后去百度了怎么判断一个点在图形内,找到一个做射线找几个交点的方法,想了一下,代码太复杂,而且怎么做线什么的都是问题,不可行
只能看题解了,具体看题解:
https://leetcode-cn.com/problems/erect-the-fence/solution/an-zhuang-zha-lan-by-leetcode-solution-75s3/
这里说一下我的简单理解
首先第一个算法,Jarvis算法,就是先确定一个最左边的点,然后依次与其他所有点连线,判断哪条连线在做左边或者最右边
具体怎么判断呢,就是通过向量叉乘的方式,两个向量叉乘,得到的是一个向量。a,b两个向量叉乘的模 |a×b| = |a|*|b|*sin(向量a,b的夹角)
(这个夹角和点乘的夹角有点不同,最大的区别就是点乘是0到180度,指的是两个向量之间的夹角,而叉乘的夹角是0到360度,是指一个向量转动到另一个向量的角度)
所以说通过这个叉乘,可以判断两个向量之间的夹角是否是大于180度的,这样就可以判断一条边是否在另一条边的左边
用这样的方法,从最左边的点开始,找最右边的边,也就是其他点都在这条边的左边
然后以新的起点出发,找新的边,保证其他点在这个边的左边,这样依次找到一个闭环,就是所要的凸包
这里有个问题,就是在所给的这个代码中,加入了visit数组,判断每个点是否被加入到res中,如果加入了,那么就不重复加入;但是这个有必要吗,或者说正确吗,如果存在这种情况的话,当找到一个已经遍历过的点q,那么再从q出发,遍历到的点还是在res中,就形成了循环,跳不出去了;当然,除非这个点就是出发点,只有这一种可能
所以这个算法要是行得通,那么必须保证加入的每一个点都不是重复点,也就是说,从任意一个新的点出发找到的另一个点形成的边都是全新的,这很显然是符合逻辑的,也就是说这个代码中,可以在判断r的时候,就判断是否在visit中出现过,但是这样就会对最后一个点造成影响,或者说加入visit的时候,判断是否是出发点就行(实际改写了一下,不太行,因为同一条线上的点会重复加入)
但是要明白这个道理,就是说不会出现循环的情况
class Solution
public int[][] outerTrees(int[][] trees)
int n = trees.length;
if (n < 4)
return trees;
//找最左下角的点
int leftMost = 0;
for (int i = 0; i < n; i++)
if (trees[i][0] < trees[leftMost][0] ||
(trees[i][0] == trees[leftMost][0] &&
trees[i][1] < trees[leftMost][1]))
leftMost = i;
List<int[]> res = new ArrayList<int[]>();
boolean[] visit = new boolean[n];
//p最开始为最左下方的点
int p = leftMost;
do
//与随便一个q相连
int q = (p + 1) % n;
//遍历其他所有点,如果pq与qr两条边的夹角大于180度,也就是这个叉集小于0,
//那么说明点r在pq的右边,那么就加q替换成r
//最后找到最右边的点,保证其他所有点都在pq的左边
for (int r = 0; r < n; r++)
/* 如果 r 在 pq 的右侧,则 q = r */
if (cross(trees[p], trees[q], trees[r]) < 0)
q = r;
/* 是否存在点 i, 使得 p 、q 、i 在同一条直线上 */
for (int i = 0; i < n; i++)
if (visit[i] || i == p || i == q)
continue;
//在用一条线上的点,要加入结果集
if (cross(trees[p], trees[q], trees[i]) == 0)
res.add(trees[i]);
visit[i] = true;
//如果当前点没有遍历过,那么加入结果集
if (!visit[q])
res.add(trees[q]);
visit[q] = true;
//下一轮从q开始出发继续找点
p = q;
//直到围城一个图形,即开始和结尾的点相遇
while (p != leftMost);
return res.toArray(new int[][]);
public int cross(int[] p, int[] q, int[] r)
return (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/erect-the-fence/solution/an-zhuang-zha-lan-by-leetcode-solution-75s3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution
public int[][] outerTrees(int[][] trees)
int n = trees.length;
if (n < 4)
return trees;
int bottom = 0;
/* 找到 y 最小的点 bottom*/
for (int i = 0; i < n; i++)
if (trees[i][1] < trees[bottom][1])
bottom = i;
swap(trees, bottom, 0);
/* 以 bottom 原点,按照极坐标的角度大小进行排序 */
Arrays.sort(trees, 1, n, (a, b) ->
int diff = cross(trees[0], a, b);
if (diff == 0)
return distance(trees[0], a) - distance(trees[0], b);
else
return -diff;
);
/* 对于凸包最后且在同一条直线的元素按照距离从大到小进行排序 */
int r = n - 1;
while (r >= 0 && cross(trees[0], trees[n - 1], trees[r]) == 0)
r--;
for (int l = r + 1, h = n - 1; l < h; l++, h--)
swap(trees, l, h);
Deque<Integer> stack = new ArrayDeque<Integer>();
stack.push(0);
stack.push(1);
for (int i = 2; i < n; i++)
int top = stack.pop();
/* 如果当前元素与栈顶的两个元素构成的向量顺时针旋转,则弹出栈顶元素 */
while (!stack.isEmpty() && cross(trees[stack.peek()], trees[top], trees[i]) < 0)
top = stack.pop();
stack.push(top);
stack.push(i);
int size = stack.size();
int[][] res = new int[size][2];
for (int i = 0; i < size; i++)
res[i] = trees[stack.pop()];
return res;
public int cross(int[] p, int[] q, int[] r)
return (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
public int distance(int[] p, int[] q)
return (p[0] - q[0]) * (p[0] - q[0]) + (p[1] - q[1]) * (p[1] - q[1]);
public void swap(int[][] trees, int i, int j)
int temp0 = trees[i][0], temp1 = trees[i][1];
trees[i][LeetCode 824. Goat Latin (山羊拉丁文)