目录

​26题:删除排序数组中的重复项​

​122题:买卖股票的最佳时机 II​

​189题:旋转数组​

​217题:存在重复元素​

​136题:只出现一次的数字​

​350题:两个数组的交集 II​

​66题:加一​

​283题:移动零​

​1题:两数之和​

​36题:有效的数独​

​48题:旋转图像​



此文章整理于2020年校招期间,当时刷了一部分Leetcode的算法题,拿到了一些大中厂的offer。数组11道经典算法题的解题思路及代码整理如下:

  • 26题:删除排序数组中的重复项

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

解题思路:

(1)反向遍历一维数组,若后者与前者相等,则置后者的值为Flag(这里的Flag取数组的第一个元素-1);可以统计出移除后新数组的长度。

(2)随后执行交换操作,具体是将不等于Flag的数放在前面,将该处位置内容置成Flag即可。同时需要考虑数组元素为null的情况。

具体代码:

 public static int removeDuplicates(int[] nums) {
//注意数组元素为零的情况。
if (nums.length != 0) {
int flag = nums[0] - 1;
int all_length = nums.length;
//将重复元素都设置成比第一个元素小的数。然后对其统计数据进行--操作。
for (int i = nums.length - 1; i > 0; i--) {
//反向计算会效果好一些。
if (nums[i] == nums[i - 1]) {
nums[i] = flag;
all_length--;
}
}
//进行元素的移动操作
for (int i = 0; i < nums.length; i++) {
if (nums[i] == flag) {
for (int j = i; j < nums.length; j++) {
if (nums[j] != flag) {
nums[i] = nums[j];
nums[j] = flag;
break;
}
}
}
}
return all_length;
} else {
return 0;
}
}

  • 122题:买卖股票的最佳时机 II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

解题思路:

       第一遍并没有很理解这个题,看了别人的代码后发现好简单。完全可以当天买当天卖的,可以用贪心法求解,策略:反向遍历,只要后一天的股票价格比前一天高,就在前一天买入,后一天卖出;反之什么也不做。

具体代码:

   public static int maxProfit(int[] prices) {
int maxprofit = 0;
for (int j = prices.length - 1; j > 0; j--) {
if(prices[j] >prices[j-1]){
maxprofit +=(prices[j] - prices[j-1]);
}
}
return maxprofit;
}

  • 189题:旋转数组

给定一个数组,将数组中的元素向右移动 个位置,其中 是非负数。

解题思路:

      如果数组为null,则return,否则对于该数组的最后一个元素,将其赋给数组的第一个元素,对于其他元素,数组中后者的值等于前者的值,向右移动k个位置,利用while循环执行k次即可。

具体代码:

 public static void rotate(int[] nums, int k) {
if(nums.length == 0){return;}
int count = 0;
int tmp = 0;
//1.每次记录的是最后一个数字,将其赋值给一个变量,然后将前者的值赋给后者。
while (count < k) {
tmp = nums[nums.length - 1];
for (int i = nums.length - 1; i > 0; i--) {
nums[i] = nums[i - 1];
}
nums[0] = tmp;
count++;
}
}

  • 217题:存在重复元素

给定一个整数数组,判断是否存在重复元素。如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

解题思路(一):

      刚开始觉得较为简单,双重循环进行遍历,若相等,则return false。发现时间复杂度太高,哪能让你轻易这么过哦,哈哈哈....然后尝试使用Hashset去解决,相比于ArrayList、LinkList。HashSet天生就是为了提高查找效率的。具体可以查看HashSet的结构:。那么然后就简单了,一遍过。若该HahsSet中不存在该元素,则add进去,若存在,则return。

解题思路(二):

      先利用Arrays数组进行排序,然后数组中的前者和后者进行对比,得出结果。Arrays.sort()使用了归并排序算法,时间复杂度为O(nlogn),好像也没有超时。

具体代码:

public static boolean containsDuplicate(int[] nums) {
if(nums.length == 0||nums.length==1) return false;
//1.对于数组元素进行遍历,若有相等,则return true,否则false,越界的判断一定要确定。但时间复杂度太高。
// for(int i = 0 ;i<nums.length-1;i++){
// for(int j = i+1;j<nums.length;j++){
// if(nums[i] == nums[j]){
// return true;
// }
// }
// }
//2.ArrayList、LinkList效率低的可怕。HashSet天生就是为了提高查找效率的。HashSetadd时若想等会新数据将被视为已经加入,而不再重复丢入链表。
HashSet<Integer> hashSet_01 = new HashSet<Integer>();
for(int i = 0 ;i<nums.length;i++){
if(hashSet_01.contains(nums[i])){
return true;
}else{
hashSet_01.add(nums[i]);
}
}
//3.先利用Arrays数组进行排序,然后对前者和后者进行对比,得出结果。
// Arrays.sort(nums);
// for(int i = 0 ;i<nums.length;i++){
// if(nums[i+1] == nums[i]){
// return true;
// }else{
// return false;
// }
// }
return false;
}

136题:只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?。

解题思路(一):

      利用HashSet进行存储,如果HashSet不包含,则add这个元素进去,否则remove掉这个元素,最后HashSet剩下一个元素利用.iterator().next();来逐个获取内容元素。

解题思路(二):

      看了大佬的做法,瞬间觉得自己low到爆,遍历一遍数组,每个相邻元素之间进行异或操作,这个时候不论两个元素有多远都会进行异或,异或之后结果为零,剩余的元素就为出现了一次的元素。

具体代码:

 public static int singleNumber(int[] nums) {
//1.利用HashSet进行存储,然后用.iterator().next();来逐个获取内容元素
if (nums.length == 1) return nums[0];
HashSet<Integer> hashSet_01 = new HashSet<Integer>();
for (int i = 0; i < nums.length; i++) {
if (hashSet_01.contains(nums[i])) {
hashSet_01.remove(nums[i]);
} else {
hashSet_01.add(nums[i]);
}
}
//获取Hahset容器中的第一个元素。啦啦啦好开心,通过啦。
return hashSet_01.iterator().next();

//用异或完美解决
// if (A == null || A.length == 0) {
// return -1;
// }
// int rst = 0;
// for (int aA : A) {
// rst ^= aA;
// }
// return rst;
}

  • 350题:两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。

说明:输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。我们可以不考虑输出结果的顺序。

启发:1.没有什么高大上的代码;2.不要惧怕问题方法的复杂度,只要能解决问题的方法就是好方法。

解题思路(一):

      利用两个动态数组进行解决,(1)将数组二赋值给动态数组一。(2)遍历数组一,若动态数组一包含该数组一内的元素,则remove掉该元素,并将该元素add进动态数组二中。(3)最后将动态数组二赋值给一个数组,return回去。

解题思路(二):

      别人的做法,利用Arrays的sort的API,进行下标递加操作。操作较为简单,再return.。

具体代码:

public static int[] intersect(int[] nums1, int[] nums2) {
ArrayList<Integer> arrayList_01 = new ArrayList<Integer>();
ArrayList<Integer> arrayList_02 = new ArrayList<Integer>();
//1.将第二个数组内的元素存储进动态数组里
for (int i = 0; i < nums2.length; i++) {
arrayList_01.add(nums2[i]);
}
//2.若包含,则添加元素进新数组,删除旧数组中的元素。
for (int i = 0; i < nums1.length; i++) {
if (arrayList_01.contains(nums1[i])) {
arrayList_02.add(nums1[i]);
arrayList_01.remove(arrayList_01.indexOf(nums1[i]));
}
}
//3.动态数组对数组的一个赋值。
int []result = new int[arrayList_02.size()];
for(int j = 0 ;j<arrayList_02.size();j++){
result[j] = arrayList_02.get(j);
}
return result;
}
//2.利用Arrays的sort方法结合若相等,则下标递加操作。计算出其总共有多大,再return.
// public int[] intersect(int[] nums1, int[] nums2) {
// if (nums1 == null || nums2 == null) return null;
// Arrays.sort(nums1);
// Arrays.sort(nums2);
// int N = nums1.length;
// int M = nums2.length;
// int L = Math.min(M, N);
// int[] temp = new int[L];
// int i = 0;
// int j = 0;
// int k = 0;
// while (i < N && j < M ) {
// if (nums1[i] < nums2[j]) i++;
// else if (nums1[i] > nums2[j]) j++;
// else {
// temp[k++] = nums1[i];
// i++;
// j++;
// }
// }
// int[] result = new int[k];
// for (int r = 0; r < k; r++) {
// result[r] = temp[r];
// }
// return result;
//}

  • 66题:加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。

解题思路:

      刚开始尝试拼接数组内元素成字符串然后转成Long类型的方法,发现转成之后超过Long的范围,故而采用了:反向遍历该数组内的元素:1.若当前位元素为9,则置零;2.若当前位元素小于9,则加一;3.若当前位元素为9且为当前位最高位时,再建一个数组,其长度为之前数组的长度加一,将其首位置1即可。

具体代码:

public static int[] plusOne(int[] digits) {
//如果最后一位小于9,则不用进位。
boolean flag = false;
for (int i = digits.length - 1; i >= 0; i--) {
//1.若当前位为9,则置零;2.若当前为小于9,则加一;3.若当前位为9且为最高位时,则执行置零设置标志位操作。
if (digits[i] == 9 && i != 0) {
digits[i] = 0;
} else if (digits[i] == 9 && i == 0) {
digits[i] = 0;
flag = true;
} else {
digits[i] += 1;
break;
}
}
if (!flag) {
return digits;
}else{
int []result = new int[digits.length+1];
result[0] = 1;
return result;
}
}

  • 283题:移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

说明:

必须在原数组上操作,不能拷贝额外的数组。

尽量减少操作次数。

解题思路(一):

      进行双重循环遍历,分为三种情况,(1)若当前两个数组元素下标相等且数组内容不等于零,则下一个;(2)若当前两个数组元素下标不等且数组内容等于零。若找到数组内容不为零的则将其赋值,并将该位置的元素内容置零。

解题思路(二):

      设置start和index两个标识。若相等,当前位置++,若不等,则检查为标识++。将当前后面所有位置零。

具体代码:

 //1.进行遍历,分为三种情况,(1)若当前两个相等,则下一个;(2)若当前两个不等,则往下去找有没有相等的。若找到则赋值,并将该位置零。
public static void moveZeroes(int[] nums) {
for (int i = 0; i < nums.length; i++) {
for (int j = i; j < nums.length; j++) {
if (nums[j] != 0 && j != i) {
nums[i] = nums[j];
nums[j] = 0;
break;
} else if (nums[j] != 0 && j == i) {
break;
}
}
}
return;
}
//2.代码更为凝练,设置start和index两个标识。若相等,当前位置++,若不等,则检查为标识++。将当前后面所有位置零。
// public void moveZeroes(int[] nums) {
// int start = 0;
// int index = 0;
// int length = nums.length;
// while(index < length){
// if(nums[index] != 0){
// nums[start] = nums[index];
// start++;
// }
// index++;
// }
// while(start < length){
// nums[start] = 0;
// start++;
// }
// }

  • 1题:两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

解题思路:

      双重循环,若两数之和则利用一个数组长度为2的数组存其当前两个位置的下标,可能因为是第一个吧,所以较为简单。

具体代码:

//1.进行双重循环的判断即可。
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(nums[i]+nums[j] == target){
int []result = {i,j};
}
}
}
return null;
}

36题:有效的数独

Leetcode数组经典十一道算法题(代码及解题思路)_校招

解题思路:

      问题较为直接,故而解决方法也较为粗暴,(1)双重循环判断每一行符合数独的条件,若不满足则return flase。(2)双重循环判断每一列符合数独的条件,若不满足则return flase。(3)判断每个 3x3 宫内是否符合数独的条件,一共九个,将其存成长度为9的一维数组(吐槽一句:计算下标真麻烦啊····),然后进行判断。只有符合这个条件的才会return true。

具体代码:

 public static boolean isValidSudoku(char[][] board) {

//1.判断每一行符合数独的条件么。
for (int k = 0; k < 9; k++) {
for (int i = 0; i < 8; i++) {
for (int j = i + 1; j < 9; j++) {
if (board[k][i] == board[k][j] && board[k][i] != '.') {
return false;
}
}
}
}
//2.判断每一列符合数独的条件。
for (int k = 0; k < 9; k++) {
for (int i = 0; i < 8; i++) {
for (int j = i + 1; j < 9; j++) {
if (board[i][k] == board[j][k] && board[i][k] != '.') {
return false;
}
}
}
}

//3.判断每个 3x3 宫内是否符合数独的条件
for (int k = 0; k < 9; k++) {
int[] test_33 = new int[9];
int m = 0;
//进行赋值操作,每九个存放到一个数组里面
if (k < 3) {
for (int i = 0; i < 3; i++) {
for (int j = 3 * k + 0; j < 3 * k + 3; j++) {
test_33[m] = board[i][j];
m++;
}
}
} else if (k >= 3 && k < 6) {
for (int i = 3; i < 6; i++) {
for (int j = 3 * (k - 3) + 0; j < 3 * (k - 3) + 3; j++) {
test_33[m] = board[i][j];
m++;
}
}
}else{
for (int i = 6; i < 9; i++) {
for (int j = 3 * (k - 6) + 0; j < 3 * (k - 6) + 3; j++) {
test_33[m] = board[i][j];
m++;
}
}
}
//进行判断
for (int i = 0; i < 8; i++) {
for (int j = i + 1; j < 9; j++) {
if (test_33[i] == test_33[j] && test_33[i] != '.') {
return false;
}
}
}
}
return true;
}

  • 48题:旋转图像

Leetcode数组经典十一道算法题(代码及解题思路)_leetcode_02

解题思路:

      第一步:每一行变为每一列,第二步:当前矩阵中的每一行中元素的每一列进行反向赋值。最终实现旋转90度。

具体代码:

public static void rotate(int[][] matrix) {
int flag = 0;
int length = matrix.length;
//调换对角元素。
for (int i = flag; i < length; i++) { //行
for (int j = flag; j < length; j++) { //列
if (i != j && matrix[i][j] != matrix[j][i]) {
int tmp = matrix[j][i];
matrix[j][i] = matrix[i][j];
matrix[i][j] = tmp;
}
}
flag++;
}
//调换每行元素。
for (int i = 0; i < length; i++) { //行
for (int j = 0; j < length/2; j++) { //列
if (matrix[i][j] != matrix[i][length - 1 - j]) {
int tmp = matrix[i][j];
matrix[i][j] = matrix[i][length - 1 - j];
matrix[i][length - 1 - j] = tmp;
}
}
}
return;
}