SingleNumber
1 Single Number http://lintcode.com/zh-cn/problem/single-number/
public class Solution {
/**
* @param A: An integer array
* @return: An integer
*/
public int singleNumber(int[] A) {
int res = 0;
if (A == null || A.length == 0) {
return res;
}
for (int i = 0; i < A.length; i++) {
res ^= A[i];
}
return res;
}
}
异或大法。
2 Single Number II http://www.lintcode.com/en/problem/single-number-ii/
public class Solution {
public int singleNumberII(int[] A) {
if (A == null || A.length == 0) {
return -1;
}
int result=0;
int[] bits=new int[32];
for (int i = 0; i < 32; i++) {
for(int j = 0; j < A.length; j++) {
bits[i] += A[j] >> i & 1;
bits[i] %= 3;
}
result |= (bits[i] << i);
}
return result;
}
}
解题思路:统计二进制每个位上1的个数并对3取模。
出现一次的数字对应位上的1会被统计出来。
3 Single Number III http://www.lintcode.com/en/problem/single-numbe-iii/
public class Solution {
/**
* @param A : An integer array
* @return : Two integers
*/
public List<Integer> singleNumberIII(int[] A) {
int xor = 0;
for (int i = 0; i < A.length; i++) {
xor ^= A[i];
}
int lastBit = xor - (xor & (xor - 1));
// int lastBit = xor & (-xor); // 两句一样的作用,只保留xor的最后一个1。
int group0 = 0, group1 = 0;
for (int i = 0; i < A.length; i++) {
if ((lastBit & A[i]) == 0) {
group0 ^= A[i];
} else {
group1 ^= A[i];
}
}
ArrayList<Integer> result = new ArrayList<Integer>();
result.add(group0);
result.add(group1);
return result;
}
}
利用异或运算。
假设两个落单数字是 A、B
2*n + 22∗n+2 个数字异或,会得到两个仅出现一次的数字的异或结果:xor = A^B。
其中我们取出xor中任何一位1,这里取最低位的1。
这个1一定是A和B中对应位上一个是1一个是0。
所以可以将所有数字分成两类,一类是该位是1的,一类是该位是0的。
分别异或起来就得到A和B了。两类数一定都是奇数个,多出来的一个分别就是A、B。
MajorityNumber
4 Majority Number http://lintcode.com/en/problem/majority-number/
public class Solution {
/*
* @param nums: a list of integers
* @return: find a majority number
*/
public int majorityNumber(List<Integer> nums) {
if (nums == null || nums.size() == 0) {
return 0;
}
int majorNumber = 0;
int count = 0;
for (Integer num : nums) {
if (count == 0) {
majorNumber = num;
count ++;
} else {
if (majorNumber == num) {
count ++;
} else {
count --;
}
}
}
return majorNumber;
}
}
严格大于一半,最终数量肯定能使count>0 且major为自己。
5 Majority Number II http://lintcode.com/en/problem/majority-number-ii/
只可能有两个数大于1/3 摩尔投票法 Moore Voting
两个count和major 最后验证是否大于1/3
public class Solution {
/**
* @param nums: A list of integers
* @return: The majority number that occurs more than 1/3
*/
public int majorityNumber(ArrayList<Integer> nums) {
// write your code
if (nums == null || nums.size() == 0) {
return -1;
}
int num1 = 0;
int num2 = 0;
int count1 = 0;
int count2 = 0;
for (int i = 0; i < nums.size(); i++) {
int newNum = nums.get(i);
if (count1 == 0) {
num1 = newNum;
count1++;
} else if (num1 == newNum) {
count1++;
} else if (count2 == 0) {
num2 = newNum;
count2++;
} else if (num2 == newNum) {
count2++;
} else {
count1--;
count2--;
}
}
count1 = 0;
count2 = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums.get(i) == num1) {
count1++;
}
if (nums.get(i) == num2) {
count2++;
}
}
return count1 > count2 ? num1 : num2;
}
}
6 Majority Number III http://lintcode.com/en/problem/majority-number-iii/
public int majorityNumber(List<Integer> nums, int k) {
// write your code here
int size = nums.size() / k;
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
for (Integer num : map.keySet()) {
if (map.get(num) > size){
return num;
}
}
return 0;
}
上面常规空间复杂度O(n),可以优化为O(k)
还是摩尔投票法,但是用map来存这k个数字,中途假如count == 0 则移除这个key
public class Solution {
/**
* @param nums: A list of integers
* @param k: As described
* @return: The majority number
*/
public int majorityNumber(ArrayList<Integer> nums, int k) {
// count at most k keys.
HashMap<Integer, Integer> counters = new HashMap<Integer, Integer>();
for (Integer i : nums) {
if (!counters.containsKey(i)) {
counters.put(i, 1);
} else {
counters.put(i, counters.get(i) + 1);
}
if (counters.size() >= k) {
removeKey(counters);
}
}
// corner case
if (counters.size() == 0) {
return Integer.MIN_VALUE;
}
// recalculate counters
for (Integer i : counters.keySet()) {
counters.put(i, 0);
}
for (Integer i : nums) {
if (counters.containsKey(i)) {
counters.put(i, counters.get(i) + 1);
}
}
// find the max key
int maxCounter = 0, maxKey = 0;
for (Integer i : counters.keySet()) {
if (counters.get(i) > maxCounter) {
maxCounter = counters.get(i);
maxKey = i;
}
}
return maxKey;
}
private void removeKey(HashMap<Integer, Integer> counters) {
Set<Integer> keySet = counters.keySet();
List<Integer> removeList = new ArrayList<>();
for (Integer key : keySet) {
counters.put(key, counters.get(key) - 1);
if (counters.get(key) == 0) {
removeList.add(key);
}
}
for (Integer key : removeList) {
counters.remove(key);
}
}
}
炒股问题
7 Best Time to Buy and Sell Stock http://www.lintcode.com/en/problem/best-time-to-buy-and-sell-stock/
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) {
return 0;
}
int max = 0;
int temp = 0;
for (int i = 1; i < prices.length; i++) {
int profit = prices[i] - prices[i - 1];
temp += profit;
if (temp < 0) {
temp = 0;
}
max = Math.max(max, temp);
}
return max;
}
贪心,当区间总和小于0 则说明该区间不用保存。
8 Best Time to Buy and Sell Stock II http://www.lintcode.com/en/problem/best-time-to-buy-and-sell-stock-ii/
public class Solution {
/**
* @param prices: Given an integer array
* @return: Maximum profit
*/
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) {
return 0;
}
int result = 0;
for (int i = 1; i < prices.length; i++) {
int profit = prices[i] - prices[i - 1];
result += profit >= 0 ? profit : 0;
}
return result;
}
}
所有递增区间
9 Best Time to Buy and Sell Stock III http://www.lintcode.com/en/problem/best-time-to-buy-and-sell-stock-iii/
10 Best Time to Buy and Sell Stock IV https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock-iv/
上述两题是一个问题,实际上都是DP
假设一共有 n 天, 那么这 n 天最多能够完成 n / 2 比交易, 也就是说, 当 k * 2 >= n 时, 就变成了 买卖股票的最佳时机 II, 反之, 我们可以作为动态规划问题解决:
定义:
globalbest[i][j] 表示前i天,至多进行j次交易时的最大获益
mustsell[i][j] 表示前i天,至多进行j次交易,并且第i天卖出手中的股票时的最大获益
状态转移:
mustsell[i][j] = max(globalbest[i - 1][j - 1], mustsell[i - 1][j]) + prices[i] - prices[i - 1]
globalbest[i][j] = max(globalbest[i - 1][j], mustsell[i][j])
边界: mustsell[0][i] = globalbest[0][i] = 0
优化: 滚动数组优化两个状态的空间至一维数组.
class Solution {
/**
* @param k: An integer
* @param prices: Given an integer array
* @return: Maximum profit
*/
public int maxProfit(int k, int[] prices) {
// write your code here
if (k == 0) {
return 0;
}
if (k >= prices.length / 2) {
int profit = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1];
}
}
return profit;
}
int n = prices.length;
int[][] mustsell = new int[n + 1][n + 1]; // mustSell[i][j] 表示前i天,至多进行j次交易,第i天必须sell的最大获益
int[][] globalbest = new int[n + 1][n + 1]; // globalbest[i][j] 表示前i天,至多进行j次交易,第i天可以不sell的最大获益
mustsell[0][0] = globalbest[0][0] = 0;
for (int i = 1; i <= k; i++) {
mustsell[0][i] = globalbest[0][i] = 0;
}
for (int i = 1; i < n; i++) {
int gainorlose = prices[i] - prices[i - 1];
mustsell[i][0] = 0;
for (int j = 1; j <= k; j++) {
mustsell[i][j] = Math.max(globalbest[(i - 1)][j - 1] + gainorlose, mustsell[(i - 1)][j] + gainorlose);
globalbest[i][j] = Math.max(globalbest[(i - 1)][j], mustsell[i][j]);
}
}
return globalbest[(n - 1)][k];
}
};
SubArray类问题
11 Subarray http://lintcode.com/en/problem/maximum-subarray/
12 Subarray II http://lintcode.com/en/problem/maximum-subarray-ii/
13 Subarray III http://lintcode.com/en/problem/maximum-subarray-iii/
14 MinimumSubarray http://lintcode.com/en/problem/minimum-subarray/
15 Maximum Subarray Difference http://lintcode.com/en/problem/maximum-subarray-difference/
16 subArray Sum http://www.lintcode.com/en/problem/subarray-sum/
17 SubArray Sum Closest http://www.lintcode.com/en/problem/subarray-sum-closest/
Ksum类问题
18 2-Sum https://www.lintcode.com/problem/two-sum/description
public class Solution {
/**
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1, index2] (index1 < index2)
*/
public int[] twoSum(int[] numbers, int target) {
if (numbers == null || numbers.length == 0) {
return new int[]{-1, -1};
}
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < numbers.length; i++) {
if (map.containsKey(numbers[i])) {
if (i < map.get(numbers[i])) {
return new int[]{i, map.get(numbers[i])};
} else {
return new int[]{map.get(numbers[i]), i};
}
} else {
map.put(target - numbers[i], i);
}
}
return new int[]{-1, -1};
}
}
O(n) O(n) 但是这种方法很难改成ThreeSum及以上,因为很难去重(只能用Set)。改用双指针来做,因为要先sort,所以O(nlgn)
public class Solution {
/*
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1 + 1, index2 + 1] (index1 < index2)
*/
class Pair {
Integer value;
Integer index;
Pair(Integer value, Integer index) {
this.value = value;
this.index = index;
}
Integer getValue() {
return this.value;
}
}
class ValueComparator implements Comparator<Pair> {
@Override
public int compare(Pair o1, Pair o2) {
return o1.getValue().compareTo(o2.getValue());
}
}
public int[] twoSum(int[] numbers, int target) {
// write your code here
//用一个pair数组记录每个numbers[i]的值和它的位置i,防止排序后不知道该元素的位置
Pair[] number = new Pair[numbers.length];
for(int i=0;i<numbers.length;i++) {
number[i] = new Pair(numbers[i], i);
}
//排序后使用双指针
Arrays.sort(number, new ValueComparator());
int L=0, R = numbers.length-1;
while(L<R) {
if( number[L].getValue() + number[R].getValue() == target) {
int t1 = number[L].index;
int t2 = number[R].index;
int[] result = {Math.min(t1,t2), Math.max(t1,t2)};
return result;
}
if( number[L].getValue() + number[R].getValue() < target) {
L++;
} else {
R--;
}
}
int[] res = {};
return res;
}
}
用了一个Pair结构,为了保存排序后的下标。
19 3-Sum http://lintcode.com/en/problem/3sum/
twosum + set去重
public class Solution {
/**
* @param numbers: Give an array numbers of n integer
* @return: Find all unique triplets in the array which gives the sum of zero.
*/
public List<List<Integer>> threeSum(int[] numbers) {
List<List<Integer>> res = new ArrayList<>();
HashSet<List<Integer>> set = new HashSet<>();
if (numbers == null || numbers.length == 0) {
return res;
}
Arrays.sort(numbers);
for (int i = 0; i < numbers.length; i++) {
if (i != 0 && numbers[i] == numbers[i - 1]) {
continue;
}
TwoSum(set, i + 1, 0 - numbers[i], numbers);
}
res.addAll(set);
return res;
}
private void TwoSum(HashSet<List<Integer>> result,
int start,
int target,
int[] numbers){
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = start; i < numbers.length; i++) {
if (map.containsKey(numbers[i])) {
if (i > map.get(numbers[i])) {
result.add(Arrays.asList(numbers[start - 1], numbers[map.get(numbers[i])], numbers[i]));
} else {
result.add(Arrays.asList(numbers[start - 1], numbers[i], numbers[map.get(numbers[i])]));
}
} else {
map.put(target - numbers[i], i);
}
}
}
}
ThreeSum 双指针法
public class Solution {
/**
* @param nums : Give an array numbers of n integer
* @return : Find all unique triplets in the array which gives the sum of zero.
*/
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
if (nums == null || nums.length < 3) {
return results;
}
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2; i++) {
// skip duplicate triples with the same first numebr
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1, right = nums.length - 1;
int target = -nums[i];
twoSum(nums, left, right, target, results);
}
return results;
}
public void twoSum(int[] nums,
int left,
int right,
int target,
List<List<Integer>> results) {
while (left < right) {
if (nums[left] + nums[right] == target) {
ArrayList<Integer> triple = new ArrayList<>();
triple.add(-target);
triple.add(nums[left]);
triple.add(nums[right]);
results.add(triple);
left++;
right--;
// skip duplicate pairs with the same left
while (left < right && nums[left] == nums[left - 1]) {
left++;
}
// skip duplicate pairs with the same right
while (left < right && nums[right] == nums[right + 1]) {
right--;
}
} else if (nums[left] + nums[right] < target) {
left++;
} else {
right--;
}
}
}
}
20 3-Sum Closest https://www.lintcode.com/problem/3sum-closest/description
public class Solution {
/**
* @param numbers: Give an array numbers of n integer
* @param target: An integer
* @return: return the sum of the three integers, the sum closest target.
*/
public int threeSumClosest(int[] numbers, int target) {
int res = Integer.MAX_VALUE;
if (numbers == null || numbers.length == 0) {
return res;
}
Arrays.sort(numbers);
for (int i = 0; i < (numbers.length - 2); i++) {
if (i != 0 && numbers[i] == numbers[i - 1]) {
continue;
}
int left = i + 1;
int right = numbers.length - 1;
while (left < right) {
int sum = numbers[i] + numbers[left] + numbers[right];
if (Math.abs(sum - target) < Math.abs(res - target)) {
res = sum;
}
if (sum == target) {
return target;
} else if (sum < target) {
left ++;
} else {
right --;
}
}
}
return res;
}
}
双指针,没啥难度
21 4-Sum http://lintcode.com/en/problem/4sum/
public class Solution {
public List<List<Integer>> fourSum(int[] numbers, int target) {
List<List<Integer>> res = new ArrayList<>();
if (numbers == null || numbers.length == 0) {
return res;
}
Arrays.sort(numbers);
for (int i = 0; i < numbers.length - 3; i++) {
if (i != 0 && numbers[i] == numbers[i - 1]) {
continue;
}
for (int j = i + 1; j < numbers.length - 2; j++) {
if (j != (i + 1) && numbers[j] == numbers[j - 1]) {
continue;
}
int left = j + 1;
int right = numbers.length - 1;
while (left < right) {
int sum = numbers[i] + numbers[j] + numbers[left] + numbers[right];
if (sum == target) {
res.add(Arrays.asList(numbers[i], numbers[j], numbers[left], numbers[right]));
left++;
right--;
while (numbers[left] == numbers[left - 1]) {
left++;
}
while (numbers[right] == numbers[right + 1]) {
right++;
}
} else if (sum > target) {
right--;
} else {
left++;
}
}
}
}
return res;
}
}
O(n3) TwoSum的套俩遍历版本,双指针法,找到了就left ++ right-- 并去重,找不到就动一下指针。
22 k-Sum http://www.lintcode.com/en/problem/k-sum/
三重背包,再做一遍
public class Solution {
/**
* @param A: An integer array
* @param k: A positive integer (k <= length(A))
* @param target: An integer
* @return: An integer
*/
public int kSum(int[] A, int k, int target) {
// 错误输入条件
if (A == null || A.length < k) {
return 0;
}
int sum = 0;
for (int i : A) {
sum += i;
}
if (sum < target) {
return 0;
} else if (sum == target) {
return 1;
}
// 状态定义 dp[i][j][t]表示从前i个物品里选出j个,和为t的最大方案个数
int[][][] dp = new int[A.length + 1][k + 1][target + 1];
// 初始化 dp[i][0][0]始终为1,因为全是正整数
for (int i = 0; i < A.length + 1; i++) {
dp[i][0][0] = 1;
}
// 递归求解
for (int i = 1; i <= A.length ; i++) {
for (int j = 1; j <= k && j <= i; j++) {
for (int t = 0; t <= target; t++) {
if (A[i - 1] <= t) {
dp[i][j][t] = dp[i - 1][j][t] + dp[i - 1][j - 1][t - A[i - 1]];
} else {
dp[i][j][t] = dp[i - 1][j][t];
}
}
}
}
// 答案
return dp[A.length][k][target];
}
}
两个注意点,
1 最内层判断 t与A[i - 1]分别赋值,而不是直接从A[i - 1]开始,这样子没有继承前i-1个物品的状态。
2 j <= i 的同时要 <=k
Quick Questions
23 快速幂 http://www.lintcode.com/en/problem/fast-power/
public class FastPower {
/**
* @param a: A 32bit integer
* @param b: A 32bit integer
* @param n: A 32bit integer
* @return: An integer
*/
public int fastPower(int a, int b, int n) {
if (n == 0){
return 1 % b;
} else if (a == 0) {
return 0;
} else if (n == 1) {
return a % b;
}
long res = 1;
long pow = a;
while (n != 0) {
if (n % 2 == 1) {
res = (res * pow) % b;
}
pow = (pow * pow) % b;
n /= 2;
}
return (int)(res % b);
}
}
非递归写法,开始没A的原因是没用long
24 Sqrt(x) http://www.lintcode.com/en/problem/sqrtx/ Magic Number 0x5f3759df
public class SqrtX {
/**
* @param x: An integer
* @return: The sqrt of x
*/
public int sqrt(int x) {
if (x < 0) throw new IllegalArgumentException();
else if (x <= 1) return x;
int start = 1, end = x;
// 直接对答案可能存在的区间进行二分 => 二分答案
while (start + 1 < end) {
int mid = start + (end - start) / 2;
// writing in this way instead of "nums[mid] * nums[mid]" to avoid overflow
if (mid == x / mid) return mid;
// possible root must be larger than or equal to current mid
else if (mid < x / mid) start = mid;
// possible root must be smaller than or equal to current mid
else end = mid;
}
if (end > x / end) return start;
return end;
}
}
二分查找法。
25 Trailing Number of zeros in n! http://www.lintcode.com/en/problem/trailing-zeros/
class Solution {
/*
* param n: As desciption
* return: An integer, denote the number of trailing zeros in n!
*/
public long trailingZeros(long n) {
long sum = 0;
while (n != 0) {
sum += n / 5;
n /= 5;
}
return sum;
}
};
蛮玄乎的,0的个数取决于5的个数。
26 O(1) Check Power of 2 http://www.lintcode.com/problem/o1-check-power-of-2/
class Solution {
/*
* @param n: An integer
* @return: True or false
*/
public boolean checkPowerOf2(int n) {
if (n <= 0) {
return false;
}
return (n & (n-1)) == 0;
}
};
二进制中只有一个1 n&(n-1)作用:将n的二进制表示中的最低位为1的改为0
Partition
27 Partition Array http://lintcode.com/en/problem/partition-array/
public class Solution {
/**
* @param nums: The integer array you should partition
* @param k: An integer
* @return: The index after partition
*/
public int partitionArray(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return 0;
}
int start = 0;
int less = start - 1;
int end = nums.length - 1;
int more = end;
while (start <= more) {
if (nums[start] < k) {
swap(nums, ++less, start++);
} else if (nums[start] == k) {
start ++;
} else {
swap(nums, more--, start);
}
}
return less + 1;
}
private void swap(int[] A, int a, int b) {
// 交换
int temp = A[a];
A[a] = A[b];
A[b] = temp;
}
}
通用Partition模板
28 Sort Letters by Case http://lintcode.com/en/problem/sort-letters-by-case/
public class Solution {
/*
* @param chars: The letter array you should sort by Case
* @return: nothing
*/
public void sortLetters(char[] chars) {
if (chars == null || chars.length == 0) {
return;
}
int start = 0;
int end = chars.length - 1;
while (start <= end) {
if (chars[start] >= 'a' && chars[start] <= 'z') {
start ++;
} else {
swap(chars, end--, start);
}
}
return;
}
private void swap(char[] A, int a, int b) {
// 交换
char temp = A[a];
A[a] = A[b];
A[b] = temp;
}
}
29 Sort Colors http://lintcode.com/zh-cn/problem/sort-colors/
public class Solution {
public void sortColors(int[] nums) {
if (nums == null || nums.length == 0) {
return;
}
int start = 0;
int less = start - 1;
int end = nums.length - 1;
while (start <= end) {
if (nums[start] == 0) {
swap(nums, ++less, start++);
} else if (nums[start] == 1) {
start++;
} else {
swap(nums, end--, start);
}
}
return;
}
private void swap(int[] A, int a, int b) {
// 交换
int temp = A[a];
A[a] = A[b];
A[b] = temp;
}
}
30 Interleaving Negative & Positive numbers http://lintcode.com/zh-cn/problem/interleaving-positive-and-negative-numbers/
class Solution {
/**
* @param A: An integer array.
* @return: void
*/
public int[] rerange(int[] A) {
// Check the input parameter.
if(A == null || A.length < 3)
return A;
int n = A.length;
int countPositive = 0;//count the number of positive numbers
// store the positive numbers index.
int positiveIndex = 0;
int pos = 1;
int neg = 0;
for(int i=0;i<n;i++) {
if(A[i] > 0) {
// Put all the positive numbers at in the left part.
swap(A,positiveIndex++,i);
countPositive++;
}
}
if(countPositive > n/2) {
// If positive numbers are more than negative numbers,
// Put the positive numbers at first.
pos = 0;
neg = 1;
// Reverse the array.
int left = 0;
int right = n-1;
while(left < right) {
swap(A,left,right);
left++;
right--;
}
}
while(pos < n && neg <n) {
while(pos<n && A[pos]>0)
pos +=2;
while(neg<n && A[neg]<0)
neg +=2;
if(neg >= n || pos>=n)
break;
swap(A,pos,neg);
}
return A;
}
public void swap(int[] A, int l, int r) {
int temp = A[l];
A[l] = A[r];
A[r] = temp;
}
}
先判断正数多还是负数多。然后每次指针+2交换