1370 上升下降字符串
给你一个字符串 s ,请你根据下面的算法重新构造字符串:
从 s 中选出 最小 的字符,将它 接在 结果字符串的后面。
从 s 剩余字符中选出 最小 的字符,且该字符比上一个添加的字符大,将它 接在 结果字符串后面。
重复步骤 2 ,直到你没法从 s 中选择字符。
从 s 中选出 最大 的字符,将它 接在 结果字符串的后面。
从 s 剩余字符中选出 最大 的字符,且该字符比上一个添加的字符小,将它 接在 结果字符串后面。
重复步骤 5 ,直到你没法从 s 中选择字符。
重复步骤 1 到 6 ,直到 s 中所有字符都已经被选过。
在任何一步中,如果最小或者最大字符不止一个 ,你可以选择其中任意一个,并将其添加到结果字符串。
请你返回将 s 中字符重新排序后的 结果字符串
class Solution {
public String sortString(String s) {
//不停地按字典序 升序追加,降序追加,每次加一个
// 动态数组 Stringbuffer其实是动态字符串数组 append 放在一起
int[] tmp = new int[26];
for(int i=0; i < s.length(); i++){
tmp[s.charAt(i) -'a']++;
}
StringBuffer ret = new StringBuffer();
while (ret.length() < s.length()) {
for(int i =0; i < 26; i++){
if (tmp[i] > 0){
ret.append((char) (i + 'a'));
tmp[i]--;
}
}
for(int i = 25; i >= 0; i--){
if (tmp[i] > 0){
ret.append((char) (i + 'a'));
tmp[i]--;
}
}
}
return ret.toString();
}
}
1470.重新排序数组
给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,…,xn,y1,y2,…,yn] 的格式排列。
请你将数组按 [x1,y1,x2,y2,…,xn,yn] 格式重新排列,返回重排后的数组。
给定的数组nums拆分成两个数组,分别存放X和Y,这样在从0遍历一次n,依次将分的2个数组存放到新数组中通过双指针的方式进行解决
class Solution {
public int[] shuffle(int[] nums, int n) {
int temp[] = new int[nums.length];
int index = 0;
for(int i = 0; i < n; i++){
temp[index++] = nums[i];
temp[index++] = nums[i+n];
}
return temp;
}
}
283.移动0
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
class Solution {
public void moveZeroes(int[] nums) {
int n = nums.length, left = 0,right = 0;
while (right < n) {
if(nums[right] != 0){
mobile(nums, left, right);
left++;
}
right++;
}
}
public void mobile(int[] nums, int left, int right){
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
164.最大间距
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。
示例 1:
输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
示例 2:
输入: [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。
方法一:基数排序
一种最简单的思路是将数组排序后再找出最大间距,但传统的基于比较的排序算法(快速排序、归并排序等)均需要 O(N\log N)O(NlogN) 的时间复杂度。我们必须使用其他的排序算法。例如,基数排序可以在 O(N)O(N) 的时间内完成整数之间的排序。
class Solution {
public int maximumGap(int[] nums) {
//需要了解stream 还有四种状态
int n = nums.length;
if(n < 2){
return 0;
}
long exp = 1;
int[] buf = new int[n];
int maxVal = Arrays.stream(nums).max().getAsInt();
while(maxVal >= exp) {
int[] cnt = new int[10];
for(int i = 0; i < n;i++){
int digit = (nums[i] / (int) exp) % 10;
cnt[digit]++;
}
for(int i = 1; i < 10; i++){
cnt[i] += cnt[i - 1];
}
for(int i = n - 1; i >= 0; i--){
int digit= (nums[i] / (int) exp) % 10;
buf[cnt[digit] -1] = nums[i];
cnt[digit]--;
}
System.arraycopy(buf, 0, nums, 0, n);
exp *= 10;
}
int ret = 0;
for(int i = 1; i < n; i++){
ret = Math.max(ret, nums[i] - nums[i - 1]);
}
return ret;
}
}
方法二
思路与算法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ssZ7OME-1607478247424)(C:\Users\heng\Desktop\snipaste20201126_185559.png)]
因此,在找出每个元素所在的桶之后,我们可以维护每个桶内元素的最大值与最小值。随后,只需从前到后不断比较相邻的桶,用后一个桶的最小值与前一个桶的最大值之差作为两个桶的间距,最终就能得到所求的答案
class Solution {
public int maximumGap(int[] nums) {
int n = nums.length;
if (n < 2) {
return 0;
}
int minVal = Arrays.stream(nums).min().getAsInt();
int maxVal = Arrays.stream(nums).max().getAsInt();
int d = Math.max(1, (maxVal - minVal) / (n - 1));
int bucketSize = (maxVal - minVal) / d + 1;
int[][] bucket = new int[bucketSize][2];
for (int i = 0; i < bucketSize; ++i) {
Arrays.fill(bucket[i], -1); // 存储 (桶内最小值,桶内最大值) 对, (-1, -1) 表示该桶是空的
}
for (int i = 0; i < n; i++) {
int idx = (nums[i] - minVal) / d;
if (bucket[idx][0] == -1) {
bucket[idx][0] = bucket[idx][1] = nums[i];
} else {
bucket[idx][0] = Math.min(bucket[idx][0], nums[i]);
bucket[idx][1] = Math.max(bucket[idx][1], nums[i]);
}
}
int ret = 0;
int prev = -1;
for (int i = 0; i < bucketSize; i++) {
if (bucket[i][0] == -1) {
continue;
}
if (prev != -1) {
ret = Math.max(ret, bucket[i][0] - bucket[prev][1]);
}
prev = i;
}
return ret;
}
}
454.四数相加 ||
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。
输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
使用二重循环对它们进行遍历,得到所有A[i] + B[j]的值 并存入哈希映射中
方法一 : 分组 + 哈希表
class Solution {
public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
Map<Integer,Integer> countAB = new HashMap<Integer,Integer>();
for(int u : A){
for(int v : B){
countAB.put(u + v,countAB.getOrDefault(u + v, 0) + 1);
}
}
int ans = 0;
for(int u : C){
for(int v : D){
if(countAB.containsKey(-u -v)){
ans += countAB.get(-u -v);
}
}
}
return ans;
}
}
方法二 : 暴力干
class Solution {
public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
Map<Integer, Integer> map = new HashMap<>();
//分组 循环 得总数 判断 是否有总数值 在添加进map +1 是数组从0开始
int res = 0;
for(int i = 0;i<A.length;i++){
for(int j= 0;j<B.length;j++){
int sumAB = A[i]+B[j];
if(map.containsKey(sumAB)) map.put(sumAB,map.get(sumAB)+1);
else map.put(sumAB,1);
}
}
for(int i = 0;i<C.length;i++){
for(int j = 0;j<D.length;j++){
int sumCD = -(C[i]+D[j]);
if(map.containsKey(sumCD)) res += map.get(sumCD);
}
}
return res;
}
}
1.两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
方法二 : 哈希表
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> hashtable = new HashMap<Integer,Integer>();
for(int i = 0; i < nums.length; i++){
if(hashtable.containsKey(target - nums[i])){
return new int[] {
hashtable.get(target - nums[i]), i
};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
493.翻转对
给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
方法一: 归并排序
思路及解法(官方)
在归并排序的过程中,假设对于数组 \textit{nums}[l…r]nums[l…r] 而言,我们已经分别求出了子数组 \textit{nums}[l…m]nums[l…m] 与 \textit{nums}[m+1…r]nums[m+1…r] 的翻转对数目,并已将两个子数组分别排好序,则 \textit{nums}[l…r]nums[l…r] 中的翻转对数目,就等于两个子数组的翻转对数目之和,加上左右端点分别位于两个子数组的翻转对数目。
我们可以为两个数组分别维护指针 i,ji,j。对于任意给定的 ii 而言,我们不断地向右移动 jj,直到 \textit{nums}[i] \le 2\cdot \textit{nums}[j]nums[i]≤2⋅nums[j]。此时,意味着以 ii 为左端点的翻转对数量为 j-m-1j−m−1。随后,我们再将 ii 向右移动一个单位,并用相同的方式计算以 ii 为左端点的翻转对数量。不断重复这样的过程,就能够求出所有左右端点分别位于两个子数组的翻转对数目。
个人理解
class Solution {
public int reversePairs(int[] nums) {
if(nums.length == 0){
return 0;
}
return reversePairsRecursive(nums, 0, nums.length - 1);
}
public int reversePairsRecursive(int[] nums, int left, int right){
if(left == right){
return 0;
} else {
int mid = (left + right) / 2;
int n1 = reversePairsRecursive(nums, left, mid);
int n2 = reversePairsRecursive(nums, mid + 1, right);
int ret = n1 + n2;
//首先 统计 下标对的数量
int i = left;
int j = mid + 1;
while (i <= mid){
while (j <= right && (long) nums[i] > 2 * (long) nums[j]){
j++;
}
ret += j - mid - 1;
i++;
}
//随后合并两个排序数组
int[] sorted = new int[right - left + 1];
int p1 = left, p2 = mid + 1;
int p = 0;
while(p1 <= mid || p2 <= right) {
if(p1 > mid){
sorted[p++] = nums[p2++];
} else if(p2 > right){
sorted[p++] = nums[p1++];
} else {
if(nums[p1] < nums[p2]){
sorted[p++] = nums[p1++];
} else {
sorted[p++] = nums[p2++];
}
}
}
for(int k = 0; k < sorted.length; k++){
nums[left + k] = sorted[k];
}
return ret;
}
}
}
976.三角形的最大周长
给定由一些正数(代表长度)组成的数组 A
,返回由其中三个长度组成的、面积不为零的三角形的最大周长。
如果不能形成任何面积不为零的三角形,返回 0
。
示例 1:
输入:[2,1,2]
输出:5
示例 2:
输入:[1,2,1]
输出:0
方法: 贪心 + 排序
class Solution {
public int largestPerimeter(int[] A) {
Arrays.sort(A);
for(int i = A.length - 1; i >= 2; --i){
if(A[i - 2] + A[i - 1] > A[i]){
return A[i - 2] + A[i - 1] + A[i];
}
}
return 0;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/unique-paths/solution/bu-tong-lu-jing-by-leetcode-solution-hzjf/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。