一、丑数
题目:
/** * 编写一个程序判断给定的数是否为丑数。 * 丑数就是只包含质因数 2, 3, 5 的正整数。 * * 示例 1: * 输入: 6 * 输出: true * 解释: 6 = 2 × 3 * * 示例 2: * 输入: 8 * 输出: true * 解释: 8 = 2 × 2 × 2 * * 示例 3: * 输入: 14 * 输出: false * 解释: 14 不是丑数,因为它包含了另外一个质因数 7。 * * 说明: * 1 是丑数。 * 输入不会超过 32 位有符号整数的范围: [−2^31, 2^31 − 1]。 */
可以直接根据丑数的判定规则进行判断,只包含2,3,5这三个质因数,那我就把这三个数除尽看看剩不剩其他的数就好了。
public static boolean method1(int num) {
if (num<1) return false;
while (num%5==0){
num/=5;
}
while (num%3==0){
num/=3;
}
while (num%2==0){
num>>=1;
}
return num == 1;
}
二、消失的数
题目:
/** * 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。 * * 示例 1: * 输入: [3,0,1] * 输出: 2 * * 示例 2: * 输入: [9,6,4,2,3,5,7,0,1] * 输出: 8 * * 说明: * 你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现? */
一种简单的解决方法,把数组排序,然后遍历判断找出
public static int method1(int[] nums) {
Arrays.sort(nums);
int i=0;
for (;i<nums.length;i++){
if (nums[i]!=i){
return i;
}
}
return i+1;
}
你还可以借助位运算,一个数异或另一个数两次等于它本身,一个数异或它自己等于0,0异或任何数等于任何数
public static int method2(int[] nums) {
int res = nums.length;
for (int i = 0; i < nums.length; ++i){
res ^= nums[i];
res ^= i;
}
return res;
}
三、移动零
题目:
/** * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 * * 示例: * 输入: [0,1,0,3,12] * 输出: [1,3,12,0,0] * * 说明: * 必须在原数组上操作,不能拷贝额外的数组。 * 尽量减少操作次数。 */
第一个想到的就是快慢指针,把快指针扫描到的非0的数字赋值到慢指针的位置,快指针走完就把从慢指针当前所在位置到数组尾全部赋值为0。
public static void method1(int[] nums) {
int fast = 0, slow = 0, count = 0;
for (; fast < nums.length; fast++) {
if (nums[fast] != 0) {
count++;
if (fast != slow) {
nums[slow] = nums[fast];
}
slow++;
}
}
for (int i = count; i < nums.length; i++) {
nums[i] = 0;
}
}
换一种写法就是当快指针扫描到的非0的数字就和慢指针为0的数字交换,我在这里还加了一个判断,快慢指针位置不相等,是因为我交换的操作没有借助第三个变量,因为其中一个数已知,只需要把快指针的数赋值到慢指针上,然后慢指针的数赋值为0就可以了。
public static void method2(int[] nums) {
int fast = 0, slow = 0;
for (; fast < nums.length; fast++) {
if (nums[fast] != 0) {
if (fast != slow) {
nums[slow] = nums[fast];
nums[fast]=0;
}
slow++;
}
}
}
四、寻找中位数
题目:
/** * 中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。 * * 例如, * [2,3,4] 的中位数是 3 * [2,3] 的中位数是 (2 + 3) / 2 = 2.5 * * 设计一个支持以下两种操作的数据结构: * void addNum(int num) - 从数据流中添加一个整数到数据结构中。 * double findMedian() - 返回目前所有元素的中位数。 * * 示例: * addNum(1) * addNum(2) * findMedian() -> 1.5 * addNum(3) * findMedian() -> 2 * * 进阶: * 如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法? * 如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法? */
你可以在插入时做文章把它在插入时就整理成有序数组,使用二分查找插入,然后找中位数时就分两种情况,一种是长度为奇数一种是长度为偶数,也可以在寻找中位数时做文章,可以使用Arrays.sort来排序数组。
List<Integer> list;
public MedianFinder() {
list = new ArrayList();
}
public void addNum(int num) {
int left = 0;
int right = list.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
int val = list.get(mid);
if (val < num) left = mid + 1;
else right = mid;
}
if (list.size() > 0 && num > list.get(list.size() - 1))
list.add(num);
else
list.add(left, num);
}
public double findMedian() {
int len = list.size();
if (len % 2 == 1)
return (double) list.get(len / 2);
else
return list.get(len / 2) / 2.0
+ list.get(len / 2 - 1) / 2.0;
}
还有一种解法就是题目中提到的进阶,假设所有的数都在0-100范围内,那你就可以定义一个长度为101的数组,存储所有数字出现的次数,定义一个count变量,在添加数字的时候对其加一,实现计数,这样就实现了排序和计数,在找中位数时根据总数量进行判断更改。假设所有的数99%出现在0-100内呢,你就要多定义两个长度来保存小于0的数出现的次数和大于100的数出现的次数,再找中位数时要注意下标的变化。
private int[] nums=new int[103];
private int count=0;
public MedianFinder() {
}
public void addNum(int num) {
if (num>100){
nums[102]=nums[102]+1;
}else if (num<0){
nums[0]=nums[0]+1;
} else {
nums[num+1]=nums[num+1]+1;
}
count++;
}
public double findMedian() {
int sum=0;
if (count%2==0){
int index=count/2;
for (int i=0;i<103;i++){
sum+=nums[i];
if (sum==index){
return (i+i-1)/2.0;
}else if (sum>index){
return i-1;
}
}
}else {
int index=count/2+1;
for (int i=0;i<103;i++){
sum+=nums[i];
if (sum>=index){
return i-1;
}
}
}
return 0;
}