LeeCode初级算法数组部分十一道题
差不多一周时间就写了11道题,纯纯废物
文章目录
1删除排序数组中的重复项
1.1自己写的
本年度写的第一道算法题有点傻,特喜欢像大一ACM那样开个一百万的数组,思路就是从第二个元素开始和前一个数判断,如果相同直接continue,不同就放入新数组中,定义一个整数记录新数组长度,最后把新数组再循环复制给原数组
package primary;
/**
* @Description:删除排序数组中的重复项
* @Author Mr.cui
* @Version V1.0.0
* @Since 1.0
* @Date 2022/5/11
*/
public class array_01 {
public static int removeDuplicates(int[] nums) {
int length= nums.length; //数组原本的长度
int LastLength=0;
int b[] = new int[1000000];
b[0]=nums[0];
for(int i=1;i<length;i++){
if (nums[i]==nums[i-1]){
continue;
}
else{
LastLength++;
b[LastLength]=nums[i];
System.out.println();
}
}
for (int i=0;i<LastLength+1;i++){
nums[i]=b[i];
}
return LastLength+1;
}
public static void main(String[] args) {
int[] a = {1,2,3,3,4,4,5,5,5};
int k = removeDuplicates(a); // 调用
System.out.println(a);
}
}
1.2他人优化算法
优化算法思路是定义一个数字p讲每个不一样的数字放到数组的前面,再定义一个数字来标记第一个不一样的数字,从前向后遍历,最后返回
package primary.array;
/**
* @Description:优化解
* @Author Mr.Cui
* @Date 2022/5/11
*/
public class array_01better {
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0) return 0;
int p = 0; //p是为了标记每一个不一样的数字
int q = 1; //q是为了标记和p所对应的数字不一样的第一个数字
// 0 1 1 2 2 2 3 3 3
while(q < nums.length){
if(nums[p] != nums[q]){
if(q - p > 1){ //这里是因为如果等于一则不需要挪位置
nums[p + 1] = nums[q];
}
p++;
}
q++;
}
return p + 1;
}
//
// 作者:max-LFszNScOfE
// 链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/solution/shuang-zhi-zhen-shan-chu-zhong-fu-xiang-dai-you-hu/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
2.买卖股票的最佳时机 II
思路是没啥思路,只要后面比前面大加起来就完事了
package primary.array;
/**
* @Description;买卖股票的最佳时机 II
* @Author Mr.Cui
* @Date 2022/5/11
*/
public class array_02 {
public static int maxProfit(int[] prices) {
int profit=0;
for(int i=1;i<prices.length;i++){
if(prices[i-1]<prices[i]){
profit+=prices[i]-prices[i-1];
}
}
return profit;
};
public static void main(String[] args) {
int[] a={7,1,5,3,6,4};
int x=maxProfit(a);
System.out.println(x);
}
}
//出生即最优
3.旋转数组
3.1 自己写的
思路就是把移动之后的数组下标对数组长度求余得到他在新数组的位置
在这里插入代码片package primary.array;
/**
* @Description:旋转数组
* @Author Mr.Cui
* @Date 2022/6/1
*/
public class array_03 {
public static int[] rotate(int[] nums, int k) {
int nums1[] = new int[nums.length];
for(int i=0;i<nums.length;i++){
nums1[i]=nums[(i-k%nums.length+nums.length)%nums.length];
System.out.println(nums1[i]);
}
return nums1;
}
public static void main(String[] args) {
int[] nums={1,2};
rotate(nums,3);
}
}
3.2优化算法
也没有优化啥,就是格式看着顺眼了点,他是把原数组按整个循环把值赋给新数组,我是创建一个新数组,然后找它在原数组中对应的位置
package primary.array;
/**
* @Description:该题优化思路是在我的基础上逆向思维,将每个原数组的值赋值到新的数组上,并且减少了特殊情况的出现
* @Author Mr.Cui
* @Date 2022/6/1
*/
public class array_03better {
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
int[] newArr = new int[n];
for (int i = 0; i < n; ++i) {
newArr[(i + k) % n] = nums[i];
}
System.arraycopy(newArr, 0, nums, 0, n);
}
}
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
4.存在重复元素
思路是先将原数组用java.util.Arrays自带的排序函数将它排序,再循环length-1次判断相邻的两个数是否相等
package primary.array;
import java.util.Arrays;
/**
* @Description:存在重复数组
* @Author Mr.Cui
* @Date 2022/6/1
*/
public class array_04 {
public static boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
for (int i =0;i<nums.length-1;i++){
if (nums[i]==nums[i+1]){
return true;
}
}
return false;
}
}
5只出现一次数组
5.1.by myself
思路:先将数组排序,然后判断数组首位的特殊情况,最后判断中间的数,返回只出现一次的数
package primary.array;
import java.util.Arrays;
/**
* @Description:只出现一次数组
* @Author Mr.Cui
* @Date 2022/6/2
*/
public class array_05 {
public static int singleNumber(int[] nums) {
int x=nums.length;
Arrays.sort(nums);
if (x==1){
return nums[0];
}
if (nums[0]!=nums[1]){
return nums[0];
}
else if (nums[x-2]!=nums[x-1]){
return nums[x-1];
}
for(int i=1;i<x-1;i++){
if(nums[i]!=nums[i-1]&&nums[i]!=nums[i+1]){
return nums[i];
}
}
return 0;
}
public static void main(String[] args) {
int[] nums={1,4,1,1,1,4,5};
System.out.println(singleNumber(nums));
}
}
5.2 other
这个方法属实惊艳到我这种算法小白了,利用异或的交换律巧妙的得出只出现一次的数字
package primary.array;
/**
* @Description:
* @Author Mr.Cui:运用异或的乘法交换律,因为异或相同的数会被抵消掉,达到最后的值为只出现一次的数的目的
* @Date 2022/6/2
*/
public class array_05better {
public int singleNumber(int[] nums) {
int ans = nums[0];
if (nums.length > 1) {
for (int i = 1; i < nums.length; i++) {
ans = ans ^ nums[i];
}
}
return ans;
//
// 作者:yinyinnie
// 链接:https://leetcode.cn/problems/single-number/solution/xue-suan-fa-jie-guo-xiang-dui-yu-guo-cheng-bu-na-y/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
}
6.两个数组的交集
6.1myself
思路是
1.先将两个数组都排序,
2.因为两个数组的交集长度不能确定,所以我这里创建一个集合来存放两个数组重复的部分,
3.然后定义两个坐标分别表示第一个数组和第二个数组的下标,然后遍历,如果i指向的值小于j指向的值,,说明i指向的值小了,i往后移一步;如果i指向的值大于j指向的值,说明j指向的值小了,j往后移一步,如果i和j指向的值相同,说明这两个值是重复的,把他加入到集合list中,然后i和j同时都往后移一步,
4.因为集合只能存放引用数据类型不能存放基本数据类型所以需要通过stream()方法拿到流对象,mapToInt拿到Int流对象,就可以toArray返回int数组了
package primary.array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Description:两个数组的交集 II
* @Author Mr.Cui
* @Date 2022/6/2
*/
public class array_06 {
public static int[] intersect(int[] nums1, int[] nums2) {
List<Integer> list=new ArrayList<>();
Arrays.sort(nums1);
Arrays.sort(nums2);
int i = 0;
int j = 0;
while (i < nums1.length && j < nums2.length) {
if (nums1[i] < nums2[j]) {
// 如果i指向的值小于j指向的值,,说明i指向
// 的值小了,i往后移一步
i++;
} else if (nums1[i] > nums2[j]) {
// 如果i指向的值大于j指向的值,说明j指向的值
// 小了,j往后移一步
j++;
} else {
// 如果i和j指向的值相同,说明这两个值是重复的,
// 把他加入到集合list中,然后i和j同时都往后移一步
list.add(nums1[i]);
i++;
j++;
}
}
// int index = 0;
// int[] res = new int[list.size()];
// for (int k = 0; k < list.size(); k++) {
// res[index++] = list.get(k);
// }
// //通过stream()方法拿到流对象,mapToInt拿到Int流对象,就可以toArray返回int数组了
int[] res = list.stream().mapToInt(Integer::intValue).toArray();
return res;
}
public static void main(String[] args) {
int[] nums1 = {1,2}; //458799
int[] nums2 = {1,1}; //44899
int[] nums3=intersect(nums1,nums2);
for (int i=0;i<nums3.length;i++){
System.out.println(nums3[i]);
}
}
}
6.2 other
优化算法是创建了一个两个数组中较小长度的数组,并且理论上copyOfRange()方法比通过stream()方法拿到流对象,mapToInt拿到Int流对象toArray返回int数组快
package primary.array;
import java.util.Arrays;
/**
* @Description:这里的优化有创建较小长度数组以及最后直接返回被复制的数组,我之前的想法是先创建一个数组接被复制的数组,浪费了空间
* 并且理论上copyOfRange()方法比通过stream()方法拿到流对象,mapToInt拿到Int流对象toArray返回int数组快
* @Author Mr.Cui
* @Date 2022/6/3
*/
public class array_06better {
public int[] intersect(int[] nums1, int[] nums2) {
int len1 = nums1.length, len2 = nums2.length;
int len = len1 < len2 ? len1 : len2;
int[] ans = new int[len];
if (len1 == 0 || len2 == 0) { //处理边界条件
return ans;
}
Arrays.sort(nums1);
Arrays.sort(nums2);
int i = 0, j = 0, k = 0;
while (i < len1 && j < len2) {
if (nums1[i] == nums2[j]) {
ans[k++] = nums1[i];
i++;
j++;
} else if (nums1[i] < nums2[j]) {
i++;
} else {
j++;
}
}
return Arrays.copyOfRange(ans, 0, k);
}
// 作者:刷题侠
// 链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/x2y0c2/?discussion=L1fh1Z
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
7.加一
这个题自己没写出来
1.这个解法的思路是从后面向前面遍历,只要小于就那么就不会进到下一位,也就是说加一后这个数的位数没有发生变化,那么直接返回该数组即可,
2.否则发生进位,将该为置为0,
3.如果遍历完数组的话说明该数所有位都是9,那么需要进位,只要将数组的第一位置为1其他都为0,返回该数组即可
package primary.array;
import java.util.Arrays;
/**
* @Description:加一
* @Author Mr.Cui
* @Date 2022/6/3
*/
public class array_07 {
public static int[] plusOne(int[] digits) {
int length = digits.length;
for (int i = length - 1; i >= 0; i--) {
if (digits[i] != 9) {
//如果数组当前元素不等于9,直接加1
//然后直接返回
digits[i]++;
return digits;
} else {
//如果数组当前元素等于9,那么加1之后
//肯定会变为0,我们先让他变为0
digits[i] = 0;
}
}
//除非数组中的元素都是9,否则不会走到这一步,
//如果数组的元素都是9,我们只需要把数组的长度
//增加1,并且把数组的第一个元素置为1即可
int temp[] = new int[length + 1];
temp[0] = 1;
return temp;
}
public static void main(String[] args) {
int[] digits={9,9,9,9};
System.out.println(Arrays.toString(plusOne(digits)));
}
}
8.移动零
8.1
我的思路是创建i和j分别标识一前一后,符合对应条件则进行对应操作
1.nums[i]==0&&nums[j]!=0:互换这俩个的值并且同时移动下标
2.nums[i]!=0:包括了nums[j]等于零和不等于零的情况,同时移动下标,不进行任何操作
3.剩下的情况只剩两个位置都是0的时候,不交换,只将j向后平移
package primary.array;
import java.util.Arrays;
/**
* @Description:移动零
* @Author Mr.Cui
* @Date 2022/6/3
*/
public class array_08 {
public static int[] moveZeroes(int[] nums) {
int l=nums.length;
if (l==1){
return null;
}
else {
int i=0;
int j=1;
while(j<l){
if(nums[i]==0&&nums[j]!=0){ //符合该条件时互换这俩位置上的值
int x=nums[j];
nums[j]=nums[i];
nums[i]=x;
i++;
}
else if (nums[i]!=0){ //包括了nums[j]等于零和不等于零的情况
i++;
}
//剩下的情况只剩两个位置都是0的时候,不交换,只将i和j向后平移
j++;
}
}
System.out.println(Arrays.toString(nums));
return nums;
}
public static void main(String[] args) {
int[] nums={0,0,0,1};
nums=moveZeroes(nums);
}
}
8.2other
这个方法的思路是;把所有非0的数推到数组的前面,后面的元素全部置为0
package primary.array;
/**
* @Description:该方法真是绝绝子,不需要考虑特殊情况,直接用后面的非零整数覆盖掉前面的,后面的直接全部改为0
* @Author Mr.Cui
* @Date 2022/6/3
*/
public class array_08better {
public void moveZeroes(int[] nums) {
if(nums==null) {
return;
}
//第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
int j = 0;
for(int i=0;i<nums.length;++i) {
if(nums[i]!=0) {
nums[j++] = nums[i];
}
}
//非0元素统计完了,剩下的都是0了
//所以第二次遍历把末尾的元素都赋为0即可
for(int i=j;i<nums.length;++i) {
nums[i] = 0;
}
}
}
9.两数之和
9.1me
两次循环,一层计算和减去第一个数组的值和第二层的数组去比较得出所求
package primary.array;
import java.util.Arrays;
/**
* @Description:
* @Author Mr.Cui
* @Date 2022/6/4
*/
public class array_09 {
public static int[] twoSum(int[] nums, int target) {
for(int i=0;i< nums.length-1;i++){
for(int j=i+1;j<nums.length;j++){
if(target-nums[j]==nums[i]){
return new int[]{i,j};
}
}
}
return null;
}
public static void main(String[] args) {
int[] a={2,7,11,15};
int target=9;
int[] target1=twoSum(a,target);
System.out.println(Arrays.toString(target1));
}
}
9.2other
该作者利用哈希映射来降低时间复杂度
package primary.array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @Description:该作者利用哈希映射来降低时间复杂度
* @Author Mr.Cui
* @Date 2022/6/4
*/
public class array_09better {
public static int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i< nums.length; i++) {
if(map.containsKey(target - nums[i])) {
return new int[] {map.get(target-nums[i]),i};
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution"); //非法参数异常
}
public static void main(String[] args) {
int[] a={2,7,11,15};
int target=9;
int[] target1=twoSum(a,target);
System.out.println(Arrays.toString(target1));
}
// 作者:guanpengchn
// 链接:https://leetcode.cn/problems/two-sum/solution/jie-suan-fa-1-liang-shu-zhi-he-by-guanpengchn/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
10.有效的数独
10.1
创建三个数组分别标识,某位数字是否已经被摆放,记录某列,某位数字是否已经被摆放,// 记录某 3x3 宫格内,某位数字是否已经被摆放,如果遍历到哪个数该数所在位置已经为true那么则不是有效的数独,反之则为有效的数独
package primary.array;
/**
* @Description:有效的数独
* @Author Mr.Cui
* @Date 2022/6/5
*/
public class array_10 {
public boolean isValidSudoku(char[][] board) {
// 记录某行,某位数字是否已经被摆放
boolean[][] row = new boolean[9][9]; //boolean数组的默认值为false
// 记录某列,某位数字是否已经被摆放
boolean[][] col = new boolean[9][9];
// 记录某 3x3 宫格内,某位数字是否已经被摆放
boolean[][] block = new boolean[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int num = board[i][j] - '0'-1;//减0是为了转化为整数.减一是为了让它和数组的下标对应上
int blockIndex = i / 3 * 3 + j / 3; // 计算属于第几个3x3宫格
if (row[i][num] || col[j][num] || block[blockIndex][num]) {
return false;
} else {
row[i][num] = true;
col[j][num] = true;
block[blockIndex][num] = true;
}
}
}
}
return true;
}
}
10,2
该算法用到了位运算,思路如下
package primary.array;
/**
* @Description:利用位运算
* @Author Mr.Cui
* @Date 2022/6/5
*/
public class array_10better {
public boolean isValidSudoku(char[][] board) {
int[] line = new int[9];
int[] column = new int[9];
int[] cell = new int[9];
int shift = 0;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
//如果还没有填数字,直接跳过
if (board[i][j] == '.')
continue;
shift = 1 << (board[i][j] - '0');
int k = (i / 3) * 3 + j / 3;
//如果对应的位置只要有一个大于0,说明有冲突,直接返回false
if ((column[i] & shift) > 0 || (line[j] & shift) > 0 || (cell[k] & shift) > 0)
return false;
column[i] |= shift;
line[j] |= shift;
cell[k] |= shift;
}
}
return true;
}
// 作者:数据结构和算法
// 链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/x2f9gg/?discussion=LKIXWG
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
11.旋转镜像
根据规律总结出来新的坐标横坐标为原坐标的纵坐标,纵坐标等于正方形的边长减一再减原横坐标,因为旋转90度,所以分成四组
package primary.array;
/**
* @Description:旋转镜像
* @Author Mr.Cui
* @Date 2022/6/5
*/
public class array_11 {
/*
* 0,0 1,0 2,0 0,2 0,1 0,0
*
* 0,1 1,1 2,1 ===>>> 1,2 1,1 1,0
*
* 0,2 1,2 2,2 2,2 2,1 2,0
* */
public void rotate(int[][] matrix) {
int length = matrix.length;
//因为是对称的,只需要计算循环前半行即可
int n = matrix.length;
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < (n + 1) / 2; ++j) {
int temp = matrix[i][j]; //因为旋转的话四个数要循环替换,所以定义一个数来存取第一个数,防止被覆盖掉
matrix[i][j] = matrix[n - j - 1][i]; //根据规律总结出来新的坐标横坐标为原坐标的纵坐标,纵坐标等于正方形的边长减一减原横坐标
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = temp;
}
}
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/rotate-image/solution/xuan-zhuan-tu-xiang-by-leetcode-solution-vu3m/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
}