文章目录
- 9.3
- [581. 最短无序连续子数组](https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/)
- [594. 最长和谐子序列](https://leetcode-cn.com/problems/longest-harmonious-subsequence/)
- [598. 范围求和 II](https://leetcode-cn.com/problems/range-addition-ii/)
- [599. 两个列表的最小索引总和](https://leetcode-cn.com/problems/minimum-index-sum-of-two-lists/)
- [605. 种花问题](https://leetcode-cn.com/problems/can-place-flowers/)
- 9.10
- 9.11
- 9.13
9.3
581. 最短无序连续子数组
难度简单
自己原来的想法一直有问题。之后用了新的做法。开辟了一个新的数组,值与给定数组一致,之后对它进行排序。然后对比两个数组不匹配的位置,得到无序部分的开始和结束位置。最后返回结果。
class Solution {
public int findUnsortedSubarray(int[] nums) {
// if(nums.length <= 1){
// return 0;
// }
// int end = nums.length - 1;
// int begin = 0;
// while(begin < nums.length - 1 && nums[begin + 1] >= nums[begin]){
// begin++;
// }
// //全部有序
// if(begin == nums.length - 1){
// return 0;
// }
// int min = nums[begin];
// int max = nums[begin];
// //找到无序数组的结束,或者说找到下一个有序数组的开始
// for(int i = begin + 1;i < nums.length;i++){
// if(nums[i] < nums[i - 1] || (nums[i] >= min && nums[i] < max) || nums[i] < min){
// min = Math.min(min, nums[i]);
// max = Math.max(max, nums[i]);
// end = i;
// }
// }
// while(begin >= 1 && nums[begin] == nums[begin - 1]){
// begin--;
// }
// System.out.println(begin + " - " + end);
// return end - begin + 1;
int[] arr = new int[nums.length];
System.arraycopy(nums, 0, arr, 0, arr.length);
Arrays.sort(arr);
int begin = 0;
int end = -1;//注意本身就满足条件的情况,也就是本身就有序
boolean flag = true;//找到了开头
for(int i = 0;i < arr.length;i++){
if(arr[i] != nums[i]){//不匹配的部分
if(flag){
begin = i;
flag = false;
}else{
end = i;
}
}
}
return end - begin + 1;
}
}
594. 最长和谐子序列
难度简单
借助一个内部类和treeMap,来统计出现的数字及频次。根据他们的值进行处理。
class Solution {
class Num{
int val;
int count;
Num(int val, int count){
this.val = val;
this.count = count;
}
}
public int findLHS(int[] nums) {
if(nums.length < 2){//长度为0或1的情况
return 0;
}
Map<Integer, Integer> map = new TreeMap<>();
for(int num : nums){
if(map.containsKey(num)){
map.put(num, map.get(num) + 1);
}else{
map.put(num, 1);
}
}
int max = 0;
int index = 0;
Num[] arr = new Num[map.size()];
for(Map.Entry<Integer, Integer> entry : map.entrySet()){
arr[index++] = new Num(entry.getKey(), entry.getValue());
}
for(int i = 0;i < arr.length - 1;i++){
Num cur = arr[i];
Num next = arr[i + 1];
if(next.val - cur.val == 1){//相邻
max = Math.max(max, cur.count + next.count);
}
}
return max;
}
}
不过可以优化。我也觉得我的做法太复杂了。看了题解之后发现,其实可以借助哈希表,一次遍历就达到要求。
class Solution {
public int findLHS(int[] nums) {
if(nums.length < 2){//长度为0或1的情况
return 0;
}
Map<Integer, Integer> map = new HashMap<>();
int res = 0;
for(int num : nums){
map.put(num, map.getOrDefault(num, 0) + 1);
if(map.containsKey(num - 1)){
res = Math.max(res, map.get(num) + map.get(num - 1));
}
if(map.containsKey(num + 1)){
res = Math.max(res, map.get(num) + map.get(num + 1));
}
}
return res;
}
}
598. 范围求和 II
难度简单
其实就是算ops中最小的公共区域。
class Solution {
public int maxCount(int m, int n, int[][] ops) {
int minRow = m;
int minColumn = n;
for(int[] arr : ops){
minColumn = Math.min(arr[1], minColumn);
minRow = Math.min(arr[0], minRow);
}
return minColumn * minRow;
}
}
599. 两个列表的最小索引总和
难度简单
两重循环。
class Solution {
public String[] findRestaurant(String[] list1, String[] list2) {
int index = Integer.MAX_VALUE;
List<String> res = new ArrayList<>();
for(int i = 0;i < list1.length;i++){
for(int j = 0;j < list2.length;j++){
if(list1[i].equals(list2[j])){
if(i + j < index){
index = i + j;
res.clear();
res.add(list1[i]);
break;
}else if(i + j == index){
res.add(list1[i]);
break;
}
}
}
}
return res.toArray(new String[res.size()]);
}
}
605. 种花问题
难度简单
遍历数组,一边遍历,一边修改。其中需要注意输入数组长度为1的特殊情况。
class Solution {
public boolean canPlaceFlowers(int[] flowerbed, int n) {
if(flowerbed.length == 0){
return n == 0;
}
if(flowerbed.length == 1){
if(flowerbed[0] == 0){
return n <= 1;
}else{
return n <= 0;
}
}
for(int i = 0;i < flowerbed.length;i++){
if(i == 0){//开始
if(flowerbed[0] == 0 && flowerbed[1] == 0){
n--;
flowerbed[0] = 1;
}
}else if(i == flowerbed.length - 1){//结束
if(flowerbed[i] == 0 && flowerbed[i - 1] == 0){
n--;
flowerbed[i] = 1;
}
}else{//中间
if(flowerbed[i] == 0 && flowerbed[i - 1] == 0 && flowerbed[i + 1] == 0){
n--;
flowerbed[i] = 1;
}
}
}
return n <= 0;
}
}
9.10
554. 砖墙
难度中等
想过用暴力法,沿着每一个位置都进行一次切割,取出其中分割砖块的最小数量。但是觉得这样的做法可能会超时。又在想别的办法。想了半天还是没有头绪。之后参照了题解才做出来。
其中需要注意的是sum是不加每个list的最后一个元素的。因为砖墙的宽度是一样的,所以加上list的最后一个元素之后,他们的总和一定等于砖墙的宽度。我就是在这里踩了坑。
class Solution {
public int leastBricks(List<List<Integer>> wall) {
Map<Integer, Integer> map = new HashMap<>();
for(List<Integer> list : wall){
int sum = 0;
for(int i = 0;i < list.size() - 1;i++){
sum += list.get(i);
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
}
int ans = wall.size();
for(int key : map.keySet()){
ans = Math.min(ans, wall.size() - map.get(key));
}
return ans;
}
}
645. 错误的集合
难度简单
借助一个数组来帮助实现
class Solution {
public int[] findErrorNums(int[] nums) {
int[] ans = new int[2];
int[] count = new int[nums.length];
for(int num : nums){
count[num - 1]++;
}
for(int i = 0;i < count.length;i++){
if(count[i] == 2){
ans[0] = i + 1;
}
if(count[i] == 0){
ans[1] = i + 1;
}
}
return ans;
}
}
646. 最长数对链
难度中等
动态规划的题,看不出来。最开始用了暴力的思想去做,但是发现很难实现。参照了题解才知道应该是动态规划的做法。
class Solution {
public int findLongestChain(int[][] pairs) {
Arrays.sort(pairs, new Comparator<int[]>(){//先排序。先按照a从小到大排序,如果a相等,则按照b从小到大排序
public int compare(int[] a, int[] b){
if(a[0] == b[0]){
return a[1] - b[1];
}
return a[0] - b[0];
}
});
int n = pairs.length;
int[] dp = new int[n];
for(int i = 1;i < n;i++){//以第i个作为结尾
for(int j = 0;j < i;j++){
if(pairs[i][0] > pairs[j][1]){//满足条件的都尝试去更新dp数组
dp[i] = Math.max(dp[j] + 1, dp[i]);//以第i个作为尾节点的最长链表长度
}
}
}
int ans = 0;
for(int num : dp){//取出其中的最大值
ans = Math.max(num, ans);
}
return ans + 1;
}
}
9.11
216. 组合总和 III
难度中等
感觉这个题和全排列差不多的思想。不过我每次做这类问题的时候,那个递归指针总是用错,分不清楚。这个题在做的时候最开始也用错了递归指针。
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> list = new LinkedList<>();
handle(list, k, n, 0, new LinkedList<Integer>(), 1);
return list;
}
public void handle(List<List<Integer>> list, int k, int n, int sum, List<Integer> path, int begin){
if(path.size() == k && sum == n){
list.add(new ArrayList<>(path));
return ;
}
for(int i = begin;i <= 9;i++){
sum += i;
path.add(i);
handle(list, k, n, sum, path, i + 1);
path.remove(path.size() - 1);
sum -= i;
}
}
}
9.13
91. 解码方法
难度中等
是一个动态规划的问题,但是我一直没找对状态转移方程,花了好多时间都没做出来。之后看了题解才知道,原来应该加上的是dp[i - 2],我一直都是用i - 1来处理。
class Solution {
public int numDecodings(String s) {
int len = s.length();
if (len == 0) {
return 0;
}
int[] dp = new int[len];
char[] charArray = s.toCharArray();
if (charArray[0] == '0') {
return 0;
}
dp[0] = 1;
for (int i = 1; i < len; i++) {
if (charArray[i] != '0') {
dp[i] = dp[i - 1];
}
int num = 10 * (charArray[i - 1] - '0') + (charArray[i] - '0');
if (num >= 10 && num <= 26) {
if (i == 1) {
dp[i]++;
} else {
dp[i] += dp[i - 2];
}
}
}
return dp[len - 1];
}
}
152. 乘积最大子数组
难度中等
最简单的做法就是暴力解决。
class Solution {
public int maxProduct(int[] nums) {
if(nums.length == 0){
return 0;
}
//最简单的方法就是暴力
int ans = Integer.MIN_VALUE;
int temp = 1;
//从i开始,到j结束
for(int i = 0;i < nums.length;i++){
temp = 1;
for(int j = i;j < nums.length;j++){
temp *= nums[j];
ans = Math.max(temp, ans);
}
}
return ans;
}
}
用动态规划优化的方法,看不懂。。。
279. 完全平方数
难度中等
这个题做了好久,尝试了好多想法都没做出来。最后还是看了题解才做出来。
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1]; // 默认初始化值都为0
for (int i = 1; i <= n; i++) {
dp[i] = i; // 最坏的情况就是每次+1
for (int j = 1; i - j * j >= 0; j++) {
dp[i] = Math.min(dp[i], dp[i - j * j] + 1); // 动态转移方程
}
}
return dp[n];
}
}
300. 最长上升子序列
难度中等
注意其中的特殊条件,比如长度为0、长度为1,分别进行处理。
class Solution {
public int lengthOfLIS(int[] nums) {
int len = nums.length;
if(len == 0){
return 0;
}
int[] dp = new int[len];//以i结尾的最长上升子序列
Arrays.fill(dp, 1);
int max = 1;
for(int i = 1;i < len;i++){
for(int j = i - 1;j >= 0;j--){
if(nums[i] > nums[j]){
dp[i] = Math.max(dp[j] + 1, dp[i]);
}
}
max = Math.max(max, dp[i]);
}
return max;
}
}