LeetCode——Array
Easy
Move Zeros
代码:
public class Solution {
public static void moveZeroes(int[] nums) {
if (nums == null || nums.length == 0) {
return;
}
int cur = 0;//该指针等到0出现的那一刻,就会一直指向0,因此需要将他所指向的元素给temp.回头给 nums[i]
// 共有cur和i两个指针,如果一开始元素不为0,那么i指向谁,cur也指向谁,
// 但后续cur++后cur会比i大1,比如i=0时,执行循环完后,cur=1 i=1时,执行完循环后cur=2;
// 但如果遇到元素为0了,i指针会继续往下走,但cur指针会停留在最后++后的地方。如i=2时,元素为0,那么循环就执行结束
// 且cur没有++,还是2。接着i=3时,执行循环,temp用来装cur所在位置的元素,即为0,再把i现在所在位置的元素移到cur位置
// ,然后cur++.最后把temp(0)移到i所在的位置。执行完毕后,cur又指向了0元素,如果下一个元素是0,i就继续往下走,直到碰到
// 非0元素,再与cur位置的元素(0)交换。
for (int i = 0; i < nums.length; ++i) { // 没碰到0元素之前,都是元素自己给自己赋值,然后交换自己。
if (nums[i] != 0) {
int temp = nums[cur];
nums[cur++] = nums[i];//将nums[i]的非0元素给0元素所在位置nums[cur++]
nums[i] = temp;
}
}
}
public static void main(String[] args) {
int[] arr=new int[] {1,3,0,1,1,0,0,0,2};
moveZeroes(arr);
for(int i:arr) {
System.out.print(i+" ");
}
}
}
交换位置那边换成如下更好理解一些:
for(int i = 0; i < nums.length; i++) {
if(nums[i] != 0) {
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
j++;
}
}
Jewels and Stones
Note:
- S and J will consist of letters and have length at most 50.
- The characters in J are distinct.
解答:
1.使用正则表达式:
class Solution {
public int numJewelsInStones(String J, String S) {
return S.replaceAll("[^"+J+"]","").length();
// return S.replaceAll("[^J]","").length();这样写会将J当作一个普通的数字,而非字符串
// [abc] : 表示可能是a,可能是b,也可能是c
// [^abc] : 表示不是a,b,c中的任意一个
}
}
2.使用集合
class Solution {
public static int numJewelsInStones(String J, String S) {
int cnt=0;
Set set=new HashSet();
for(char s:J.toCharArray()) {//将J中的字母都扔到集合中
set.add(s);
}
for(char s:S.toCharArray()) {
if(set.contains(s)) {//挨个看看S中的字符set集合中是否拥有
cnt++;
}
}
return cnt;
}
public static void main(String[] args) {
int cnt=numJewelsInStones("abc","213sd2ac");
System.out.println(cnt);//2
}
}
344. Reverse String
解答:
1.两个指针一前一后扫描交换
class Solution {
public void reverseString(char[] s) {
int i = 0;
int j = s.length - 1;
while (i < j) {
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
}
169.Majority Element
代码:
public class Solution {
public int majorityElement(int[] num) {
/*
* 设置一个指针用来计数,指向第一个元素,此时指针值为1,然后以此往后
* 碰到相同元素,指针值+1,否则-1,如果指针值为0,说明此时并没有一个值more than
* n/2。但也存在一个问题,如果数组里没有元素>n/2,那会出问题,如,1,2,3,4,5
* 最终count=1,return的element是5,但显然5不符合要求。因此假设数组中
* 总是存在the majority element十分重要。
*/
int major=num[0], count = 1;
for(int i=1; i<num.length;i++){
if(count==0){
count++;
major=num[i];
}else if(major==num[i]){
count++;
}else count--;
}
return major;
}
}
代码图解:
242. Valid Anagram
代码:
public class Solution {
public boolean isAnagram(String s, String t) {
int[] alphabet = new int[26];
for (int i = 0; i < s.length(); i++) //跟计数/桶排序一样,往桶(0-26范围)里面存值
alphabet[s.charAt(i) - 'a']++; //注意一下,arr['b'-'a']等价于arr[1]。即arr['b'-'a']==arr[1]
for (int i = 0; i < t.length(); i++) //在对应的桶里面取值
alphabet[t.charAt(i) - 'a']--;
for (int i : alphabet) //如果两个数组的元素都是一样的话,那此时桶对应的值应该都为0。
if (i != 0) return false;
return true;
}
}
注意:
数组的长度表示可以用arr.length,而字符串的长度表示要用s.length();
s.charAt(i) - 'a’这样能够保证这差值是大于等于0,小于等于25的——‘a’=97,‘z’=122,122-97=25。长度是122-97+1=26。所以alphabet数组长度为26.
217. Contains Duplicate
代码:
我自己做的:一个简单的计数排序搞定
class Solution {
public boolean containsDuplicate(int[] nums) {
int max=nums[0];
for(int i:nums){
if(i>max) max=i;
}
int[] bask=new int[max+1];
for(int i:nums){
bask[i]++;
}
boolean flag=false;
for(int i:bask)
if(i>1)
flag= true;
return flag;
}
}
第二种方法:使用HashTable
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> distinct=new HashSet<Integer>();
for(int i:nums){
if(distinct.contains(i))//若集合中存在,那么代表是重复的。
return true;
else
distinct.add(i);//不重复就将该元素添加进集合中。
}
return false;
}
}
第三种方法,先排序,再比较也是一种不错的思路
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);//先排序
for(int ind = 1; ind < nums.length; ind++){
if(nums[ind] == nums[ind - 1]) {
return true;
}
}
return false;
}
最大子列和问题
122. Best Time to Buy and Sell Stock II
该题可以分段求和,并非求最大子列和问题,因此会简单许多。
代码:
public class Solution {
public int maxProfit(int[] prices) {
//price={7,1,5,4,6,3}
int total = 0;
for (int i = 0; i < prices.length - 1; i++) {
if (prices[i + 1] > prices[i])
total += prices[i + 1] - prices[i];
}
return total;
}
}
这边给出了7,1,5,4,6,3。
显然,5-1以及6-4这两段之和为最大值。
第二种写法:
class Solution {
public int maxProfit(int[] prices) {
int maxCur=0;
for(int i=1;i<prices.length;i++){
maxCur=maxCur+(prices[i]-prices[i-1]>0 ? prices[i]-prices[i-1]:0);
}
return maxCur;
}
}
121. Best Time to Buy and Sell Stock
这是一道最大子列和问题:
代码:
public class Solution {
public int maxProfit(int[] prices) {
int maxCur = 0, maxSoFar = 0;
for (int i = 1; i < prices.length; i++) {
maxCur = Math.max(maxCur += prices[i] - prices[i - 1], 0);
//maxCur=maxCur+Math.max(0,prices[i]-prices[i-1]);适用于可以分段求和的情况,而非这边的连需求和情况。
maxSoFar = Math.max(maxCur, maxSoFar);
}
return maxSoFar;
}
}
注:这边的maxCur = Math.max(0, maxCur += prices[i] - prices[i - 1]);
等同于maxCur = Math.max(0, maxCur + prices[i] - prices[i - 1]);
maxCur用来存储当前的子列和情况,只要不小于0,就会一直累加。
maxSoFar用来存储目前位置的最大子列和。
原理图:
53. Maximum Subarray
最大子列和问题
下面这种方法具有很大普遍性,针对全是复数的数组也适用。
代码:
public class Solution {
public static int maxSubArray(int[] A) {
int n=A.length;
int maxCur=A[0];
int maxAll = A[0];
for (int i = 1; i < n; i++) {
maxCur = (maxCur > 0 ? maxCur : 0) + A[i];
//(maxCur > 0 ? maxCur : 0)等价于Math.max(maxCur,0)
//好好体会上面这行代码,意味深长,如果有正有负的数组第一个元素是负数,
//那么判断下来maxCur>0不成立,置为0,maxCur=A[1];
maxAll = Math.max(maxCur, maxAll);
}
return maxAll;
}
}
注:
上边代码中maxCur与maxAll不能取为0,因为碰到元素都为负数的情况,会出错。因为元素都是负数,maxAll就会一直取0,但0并非给定数组中的元素。
总结:连续求最大和问题必须要用两个指针(maxCur和maxAll),分段求和问题只需要使用一个指针(最简单的情况)。
202. Happy Number
这是一道Floyd判圈算法(Floyd Cycle Detection Algorithm)
该算法的原理:龟兔绕着圆环赛跑
代码:
public class Solution {
public static boolean isHappy(int n) {
int slow = n;
int fast = n;
do {
slow = digitSquareSum(slow);
fast = digitSquareSum(fast);
fast = digitSquareSum(fast); //为什么fast有两个,目的就是为了让快的指针追上慢的指针
} while (slow != fast); //直到slow=fast,该do-while循环才结束
if (slow == 1)
return true;
else
return false;
}
// 用来求一个数每个数字的平方和
public static int digitSquareSum(int n) {
int sum = 0, tmp = 0;
while (n != 0) {
tmp = n % 10;
sum += tmp * tmp;
n /= 10;
}
return sum;
}
public static void main(String[] args) {
boolean num = isHappy(19);
System.out.println(num);
}
}
至于为什么fast与slow相等就停呢?因为继续往下走,永远都是一样的结果了。可以动手再试试。
代码2:
使用Set集合
public class Solution {
public static boolean isHappy(int n) {
Set<Integer> set = new HashSet<Integer>();
int squareSum=0, remain=0;
while (set.add(n)==true) { //直到出现与集合中有重复的数字才停止
// 如果出现重复数字,也就意味着下面的这段循环操作等都是重复的
squareSum = 0;
while (n > 0) { //求各项数字之和
remain = n % 10;
squareSum += remain * remain;
n /= 10;
}
if (squareSum == 1)
return true;
else
n = squareSum;//如果和不等于1就赋给n,继续计算,直到和为1或者集合中已经有这个值位置
}
return false;
}
public static void main(String[] args) {
boolean num = isHappy(20);
System.out.println(num);
}
}