一、完全平方數
題目:
/** *給定一個正整數 num,編寫一個函數,如果 num 是一個完全平方數,則返回 True,否則返回 False。 * 說明:不要使用任何內置的庫函數,如 sqrt。 * * 示例 1: * 輸入:16 * 輸出:True * * 示例 2: * 輸入:14 * 輸出:False */
不使用庫函數來判斷一個數是不是一個完全平方數-----》判斷該數開平方是不是一個整數------》從0到該數之前有沒有一個數字是該數開平方的根-----》二分查找 是否存在一個數的平方等於該數字
public boolean method1(int num) {
if(num == 0) return true;
int left = 1, right = num < 46340 ? num : 46340, temp = 0;
while(left <= right){
temp = (left + (right - left) / 2);
if(num > temp * temp){
left = temp + 1;
}else if(num == temp * temp){
return true;
}else{
right = temp - 1;
}
}
return false;
}
利用數學知識,找規律
1=1
4=1+3
9=1+3+5
16=1+3+5+7
25=1+3+5+7+9
發現了嗎?完全平方數肯定是前n個連續奇數的和 n^2=1+3+5+7+9+…+(2n-1)
利用這樣規律從1開始減,不斷的減,看最後是否可以等於0;
public boolean method2(int num) {
int sumnum = 1; while(num>0){
num-=sumnum;
sumnum+=2;
}
return num==0;
}
二、數組的交集 I
題目:
/** * 給定兩個數組,編寫一個函數來計算它們的交集。 * <p> * 示例 1: * 輸入: nums1 = [1,2,2,1], nums2 = [2,2] * 輸出: [2] * <p> * 示例 2: * 輸入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] * 輸出: [9,4] * <p> * 說明: * 輸出結果中的每個元素一定是唯一的。 * 我們可以不考慮輸出結果的順序。 */
如果這道題用python來解的話就十分簡單了,因爲python支持set運算,直接一行代碼就出來了
return list(set(nums1) & set(nums2))
java中也實現了功能相同的方法,不過set和數組轉換就不如python那般簡單了
public int[] method1(int[] nums1, int[] nums2) {
Set<Integer> integers = new HashSet<>();
for (int a : nums1) {
integers.add(a);
}
Set<Integer> integers1 = new HashSet<>();
for (int a : nums2) {
integers1.add(a);
}
integers.retainAll(integers1);
int[] ints = new int[integers.size()];
int i = 0;
for (int a : integers) {
ints[i] = a;
i++;
}
return ints;
}
也可以不使用該函數,而是自己去一個個判斷元素是否存在,實際上retainAll函數內部也是這麼實現的
public int[] method2(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
Set<Integer> set3 = new HashSet<>();
for (int i : nums1) {
set1.add(i);
}
for (int i : nums2) {
if (set1.contains(i))
set3.add(i);
}
int[] result = new int[set3.size()];
int i = 0;
for (Integer integer : set3) {
result[i++] = integer;
}
return result;
}
我們也可以先對其進行排序,隨後再用倆指針去判斷是否存在相等的元素,這樣的效率更高一些,但寫起來很是麻煩,需要很多判斷
public int[] method3(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int i = 0,j=0,k=0;
while (i < nums1.length && j < nums2.length) {
if (nums1[i] == nums2[j]) {
nums1[k++] = nums1[i];
i++;
while (i < nums1.length && nums1[i] == nums1[i - 1]) {
i++;
}
j++;
while (j < nums2.length && nums2[j] == nums2[j - 1]) {
j++;
}
} else if (nums1[i] < nums2[j]) {
i++;
while (i < nums1.length && nums1[i] == nums1[i - 1]) {
i++;
}
} else {
j++;
while (j < nums2.length && nums2[j] == nums2[j - 1]) {
j++;
}
}
}
int[] ret = new int[k];
for (int l = 0; l < k; l++) {
ret[l] = nums1[l];
}
return ret;
}
借鑑一下之前用過很多次的把元素轉換成數組下標的方式,一遍循環賦值,一遍循環查找並計數,一遍賦值數組,返回結果,因爲是操作的數組,所以這種的效率是最高的,但如果其中出的數字少但跨度大,所需的內存就會多出好多。
public int[] method4(int[] nums1, int[] nums2) {
// 確定數組 nums1 的取值範圍
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int num : nums1) {
if (num > max) {
max = num;
}
if (num < min) {
min = num;
}
}
boolean[] arr = new boolean[max - min + 1];
for (int num : nums1) {
arr[num - min] = true;
}
// 判斷數組 nums2 中的數是否在數組 nums1 中存在,
// 如果存在保存在數組 tmp 中
int[] tmp = new int[max - min + 1];
int idx = 0;
for (int num : nums2) {
if (num >= min && num <= max && arr[num - min]) {
tmp[idx++] = num;
arr[num- min] = false;
}
}
// 返回結果
int[] ret = new int[idx];
for (int i = 0; i < idx; i++) {
ret[i] = tmp[i];
}
return ret;
}
三、數組的交集 II
題目:
/** * 給定兩個數組,編寫一個函數來計算它們的交集。 * * 示例 1: * 輸入: nums1 = [1,2,2,1], nums2 = [2,2] * 輸出: [2,2] * * 示例 2: * 輸入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] * 輸出: [4,9] * * 說明: * 輸出結果中每個元素出現的次數,應與元素在兩個數組中出現的次數一致。 * 我們可以不考慮輸出結果的順序。 * * 進階: * 如果給定的數組已經排好序呢?你將如何優化你的算法? * 如果 nums1 的大小比 nums2 小很多,哪種方法更優? * 如果 nums2 的元素存儲在磁盤上,磁盤內存是有限的,並且你不能一次加載所有的元素到內存中,你該怎麼辦? */
這道題就是上面那道題的進階,多了一個數字出現次數的規則。那第一時間想到的就是Map解決,先統計每個數字出現的次數,然後比對運算。代碼超簡單。
public int[] method3(int[] nums1, int[] nums2) {
HashMap<Integer,Integer> integerHashMap=new HashMap<>();
for (int a:nums1){
integerHashMap.put(a,integerHashMap.getOrDefault(a,0)+1);
}
ArrayList<Integer> integers=new ArrayList<>();
for (int a:nums2){
if (integerHashMap.get(a)!=null&&integerHashMap.get(a)>0){
integerHashMap.put(a,integerHashMap.get(a)-1);
integers.add(a);
}
}
int[] ints=new int[integers.size()];
for (int i=0;i<ints.length;i++){
ints[i]=integers.get(i);
}
return ints;
}
類似的事情也可以使用集合來實現啊,集合可以再比對完後使用remove移除指定元素
public int[] method1(int[] nums1, int[] nums2) {
List<Integer> list1 = new ArrayList<>();
for (int num : nums1) {
list1.add(num);
}
List<Integer> list2 = new ArrayList<>();
for (int num : nums2) {
if (list1.contains(num)) {
list2.add(num);
// 從 list1 除去已匹配的數值
list1.remove(Integer.valueOf(num));
}
}
int[] res = new int[list2.size()];
int i = 0;
for (int num : list2) {
res[i++] = num;
}
return res;
}
最近學了java8(出了好久好久了。。。。),來用java8寫一遍
public int[] method2(int[] nums1, int[] nums2) {
List<Integer> list1 = Arrays.stream(nums1)
.boxed()
.collect(Collectors.toList());
List<Integer> list2 = Arrays.stream(nums2)
.boxed()
.filter(num -> {
if (list1.contains(num)) {
list1.remove(num);
return true;
}
return false;
})
.collect(Collectors.toList());
int[] res = new int[list2.size()];
for (int i = 0; i < list2.size(); i++) {
res[i] = list2.get(i);
}
return res;
}
還是像上一道題那樣預排序一下,然後使用兩個指針比對
public int[] method4(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
List<Integer> list = new ArrayList<>();
for (int i = 0, j = 0; i < nums1.length && j < nums2.length; ) {
if (nums1[i] < nums2[j]) {
i++;
} else if (nums1[i] > nums2[j]) {
j++;
} else {
list.add(nums1[i]);
i++;
j++;
}
}
int[] res = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
res[i] = list.get(i);
}
return res;
}
在java中可以使用Arrays.copyof來copy數組,如果只在數組上進行操作會快上不少,和上一種方法同一種思路,最後使用Arrays.copyof來替代一次for循環和list的使用。
public int[] method5(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int i = 0, j = 0;
int [] ans = new int [nums2.length];
int index = 0;
while(i++ < nums1.length && j++ < nums2.length){
if(nums1[i - 1] == nums2[j - 1])
ans[index++] = nums1[i - 1];
else if(nums1[i - 1] < nums2[j - 1])
j--;
else
i--;
}
return Arrays.copyOf(ans, index);
}