题目:
/** *给定一个正整数 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;
}
题目:
/** * 给定两个数组,编写一个函数来计算它们的交集。 ** 示例 1: * 输入: nums1 = [1,2,2,1], nums2 = [2,2] * 输出: [2] *
* 示例 2: * 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] * 输出: [9,4] *
* 说明: * 输出结果中的每个元素一定是唯一的。 * 我们可以不考虑输出结果的顺序。 */
如果这道题用python来解的话就十分简单了,因为python支持set运算,直接一行代码就出来了
return list(set(nums1) & set(nums2))
java中也实现了功能相同的方法,不过set和数组转换就不如python那般简单了
public int[] method1(int[] nums1, int[] nums2) {
Set integers = new HashSet<>();
for (int a : nums1) {
integers.add(a);
}
Set 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 set1 = new HashSet<>();
Set set2 = new HashSet<>();
Set 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;
}
题目:
/** * 给定两个数组,编写一个函数来计算它们的交集。 * * 示例 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 integerHashMap=new HashMap<>();
for (int a:nums1){
integerHashMap.put(a,integerHashMap.getOrDefault(a,0)+1);
}
ArrayList 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
类似的事情也可以使用集合来实现啊,集合可以再比对完后使用remove移除指定元素
public int[] method1(int[] nums1, int[] nums2) {
List list1 = new ArrayList<>();
for (int num : nums1) {
list1.add(num);
}
List 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 list1 = Arrays.stream(nums1)
.boxed()
.collect(Collectors.toList());
List 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 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);
}