1、A+B问题 给出两个整数a和b, 求他们的和, 但不能使用 +
等数学运算符
思路:作异或得到未进位和,作与并向左移1位得到进位,随后再重复操作俩结果,直到进位为0,适合用递归

public int aplusb(int a, int b) { int sum = a ^ b; int ca = (a & b) << 1; if (ca == 0) { return sum; } return aplusb(sum, ca); }
2016-12-07
2、尾部的零 设计一个算法,计算出n阶乘中尾部零的个数
思路:有多少个5因子尾部就有多少个0,除以一次5获得包含5的一次方的个数,除以两次5获得包含5的两次方的个数(两次方有两个5因子)...以此直到除以5为0跳出

public long trailingZeros(long n) { long num = 0; while (n != 0){ num += n / 5; n /= 5; } return num; }
2016-12-07
3、统计数字 计算数字k在0到n中的出现的次数,k可能是0~9的一个值
tips:由于k是0~9的值,循环时可在k开始,因为小于k的数不可能含有k
思路1:(强行获得)把所有0到n的数转成字符串,toCharArray()后用字符数组的每一位与k比较(先把每一位字符通过Character.getNumericValue()变回个位整数)

public int digitCounts(int k, int n) { int num = 0; for (int i = k; i <= n; i++){ //整数变成字符串 String s = String.valueOf(i); //字符串变成字符数组 char[] ss = s.toCharArray(); for (int j = 0; j < s.length(); j++){ //字符变成整数 int a = Character.getNumericValue(ss[j]); if (a == k){ num++; } } } return num; }
思路2:(数学方法获得)通过与10的余数得到末位,通过与10除去掉末位,构成一个循环,就可以分析一个数的所有位。然后把所有位都加起来(从局部到整体)

public int digitCounts(int k, int n) { int cnt = 0; for (int i = k; i <= n; i++) { //分次计算每一个数中含有k的个数 cnt += singleCount(i, k); } return cnt; } public int singleCount(int i, int k) { //排除0的情况 if (i == 0 && k == 0) return 1; int cnt = 0; while (i > 0) { //判断末尾是否为k if (i % 10 == k) { cnt++; } //去掉末尾再次循环,直到去除完所有位跳出循环 i = i / 10; } return cnt; }
2016-12-08
4、丑数II 设计一个算法,找出只含素因子2,3,5的第n大的数
思路1:(时间复杂度为O(n))ArrayList动态数组保存每个满足条件的数,用三个指针遍历之前的数,分别与2,3,5相乘,得到相乘后能够比数组中的上一个数大的位置,最后把这三个指针所得结果的最小值加入数组中

public int nthUglyNumber(int n){ List<Integer> uglys = new ArrayList<Integer>(); //创建整形动态数组; uglys.add(1); //把特殊值1首先加入; //分别代表了与2、3、5相乘元素的序号,相当于指针; int p2 = 0, p3 = 0, p5 = 0; //用前面各个位置的数与2,3,5相乘直到比上一个数大,并获得相应位置; for (int i = 0; i <= n - 2; i++){ //获取数组中上一个元素,第n个数的上一个对应下标为n-2; int lastNumber = uglys.get(i); while (uglys.get(p2) * 2 <= lastNumber) p2++; while (uglys.get(p3) * 3 <= lastNumber) p3++; while (uglys.get(p5) * 5 <= lastNumber) p5++; //对比p2,p3,p5位置上分别与2,3,5相乘的结果,最小值添加为下一元素; uglys.add(Math.min(Math.min(uglys.get(p2) * 2, uglys.get(p3) * 3), uglys.get(p5) * 5)); } return uglys.get(n - 1); }
思路2:(时间复杂度为O(nlogn))Map来做,还没看懂答案
2016-12-08
5、在数组中找出第k大元素
思路:利用快排思想,切分位置和k对应就是第k大(由于快排是从小到大,所以对k进行转换)
warm:好好理解切分思想和递归思想

public int kthLargestElement(int k, int[] nums) { if (nums == null || nums.length == 0) { return -1; } if (k <= 0) { return 0; } //使用快速排序,两指针为头尾,从小到大排序,需要转换第几大 return helper(nums, 0, nums.length - 1, nums.length - k + 1); } public int helper(int[] nums, int l, int r, int k) { if (l == r) { return nums[l]; } //循环切分,直到找到第k大的数,不满足就递归 int position = partition(nums, l, r); if (position == k - 1) { return nums[position]; } else if (position < k - 1) { return helper(nums, position + 1, r, k); } else { return helper(nums, l, position - 1, k); } } public int partition(int[] nums, int l, int r) { //初始化左右指针,定义切分元素 int left = l; int right = r; int pivot = nums[left]; //进行切分,右边元素小于pivot时赋给左边,否则移动 while (left < right) { while (left < right && nums[right] >= pivot) { right--; } //第一次循环时切分元素原位置上的数被取代 nums[left] = nums[right]; while (left < right && nums[left] <= pivot) { left++; } nums[right] = nums[left]; } nums[left] = pivot; return left; }
2016-12-15
6、合并两个排序的整数数组A和B变成一个新的数组
思路:先把两个数组都不溢出的情况考虑完,再判断哪一个溢出,一个溢出则另一个肯定不溢出

public int[] mergeSortedArray(int[] A, int[] B) { int m = A.length; int n = B.length; int[] C = new int[m + n]; int i = 0, j = 0, k = 0; while (i < m && j < n) { if (A[i] < B[j]) { C[k++] = A[i++]; } else { C[k++] = B[j++]; } } while (i < m) { C[k++] = A[i++]; } while (j < n) { C[k++] = B[j++]; } return C; }
2016-12-15