- 1. Window Sum
- 2. Remove Duplicates
- 3. Remove Zeroes
- 4. Valid Palindrome - too easy
- 5. Rotate String
- 6. Recover Rotated Sorted Array
- 7. Two Sum - Less Than Or Equal To Target
- 8. Two Sum - Greater Than Target
- 9. Two Sum - Closest To Target
- 10. 3Sum
- 11. 4Sum
- 12. Two Sum - Diff Equals To Target
- 13. 3 Sum Closest
- 14. Parittion Array
- 15. Quick Select算法
- 16. Partition Array By Odd and Even
- 17. Interleaving positive and negative numbers
- 18. Sort Letters By Case
- 19. Sort Colors
- 20. Sort Colors II
- 21. Array Partition I on LeetCode
- 22. Longest Substring Without Repeating Characters
Sorting Algorithms会有另一篇blog来讨论,这里先focus在习题上面。
1. Window Sum - LintCode
Description
Given an array of n integer, and a moving window(size k), move the window at each iteration from the start of the array, find the sum of the element inside the window at each moving.
Example
For array [1,2,7,8,5], moving window size k = 3.
1 + 2 + 7 = 10
2 + 7 + 8 = 17
7 + 8 + 5 = 20
return [10,17,20]
思路总结:再找一个“平行数组“:根据题目意思可以推断出来return的数组的size应该是原数组的length - 1 + k的长度。这里我们无需一个个地加每个数字,可以利用“新sum是旧sum抛弃第一个数字再加上原数组第i-1+k数字”这个规律。
public class Solution {
/**
* @param nums a list of integers.
* @return the sum of the element inside the window at each moving.
*/
public int[] winSum(int[] nums, int k) {
if (nums == null || nums.length == 0){
return new int [0];
}
int [] res = new int [nums.length - k + 1];
for (int i = 0; i < k; i++){
res[0] += nums[i];
}
for (int i = 1; i < res.length; i++){
res[i] = res[i - 1] - nums[i - 1] + nums[i - 1 + k];
}
}
}
8. Rotate String LintCode
套路:把整个string先全部翻转过来,然后分两个部分再次翻转(分割线就在k那个地方)。很多题目都是相似操作。比如Leetcode的Rotate List。
public class Solution {
/**
* @param str: An array of char
* @param offset: An integer
* @return: nothing
*/
public void rotateString(char[] str, int offset) {
// write your code here
if (str == null || str.length == 0){
return;
}
int k = offset % str.length;
// Reverse the entire String
reverse(str, 0, str.length - 1);
// Reverse the first half part: 0 to k -1
reverse(str, 0, k-1);
// Reverse the second half of the string: from k to the end
reverse(str, k, str.length - 1);
}
private void reverse (char[] s, int i, int j){
while (i <= j){
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
}
9. [LintCode] 533 Two Sum - Closest to target
Description
Given an array nums of n integers, find two integers in nums such that the sum is closest to a given number, target.
Return the difference between the sum of the two integers and the target.
Example
Given array nums = [-1, 2, 1, -4], and target = 4.
The minimum difference is 1. (4 - (2 + 1) = 1).
Challenge
Do it in O(nlogn) time complexity. -> 可以排序Arrays.sort()
这个题很简单,在two sum双指针的基础上再对现在的两个数之差进行比较,打擂台找到最小的difference。
//9. Two Sum - Closest to target
// Given an array of n integers, find two integers in nums such that the sum is closest //to a given number, target. Return the difference between the sum of the two integers //and the target.
public int twoSumClosest (int[] nums, int target){
if (nums == null || nums.length == 0){
return -1;
}
Arrays.sort(nums);
int i = 0;
int j = nums.length - 1;
int best = Integer.MAX_VALUE;
while (i < j){
int diff = Math.abs((nums[i] + nums[j]) - target);
int temp = nums[i] + nums[j];
best = Math.min(best, diff);
if (temp > target){
j--;
} else {
i++;
}
}
return best;
}
14. Partition Array by LintCode
不需要排序(排序了就没意义了),把数组以k为界限,分成左右两部分。要求左边比k小,右边大于等于k。return第一个大于等于K的数字的idnex。同样,用双指针的办法, 先找出左边第一个大于等于K的数字,与右边小于K的数字【置换】,直到两个指针相邻。跳出循环后判断return的条件即可。
// 14. Partition Array - LintCode
// Given an array nums of integers and an int k, partition the array (i.e move th
// elements in "nums") such that:
// All elements < k are moved to the left
// All elements >= k are moved to the right
// Return the partitioning index, i.e the first index i nums[i] >= k.
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) {
// write your code here
if (nums == null || nums.length == 0) {
return 0;
}
// Two Pointers
int i = 0;
int j = nums.length - 1;
while ( i < j ) {
// Fing the first value in the left side that
// is bigger than k
while ( i < j && nums[i] < k){
i++;
}
// Find the first value in the right side that is
// smaller than k
while ( i < j && nums[j] >= k){
j--;
}
// Swap two values
if ( i < j ){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
i++;
j--;
}
}
if (nums[i] < k){
return i + 1;
} else {
return i;
}
}
}
17. LintCode: Interleaving Positive and Negative Numbers
给定一个数组,要求你in-place的条件下把这个数组partition成正负交叉的情况。这个题并没有说清楚正负数的数量是不是最大相差为1,但是Looks like it is。所以我们只需要判断究竟是正数更多还是负数更多即可。哪种数字多就以哪种数字开头。
public class Solution {
/*
* @param A: An integer array.
* @return: nothing
*/
public void rerange(int[] A) {
// write your code here
// Edge Case
if (A == null || A.length < 3){
return;
}
int length = A.length;
int postiveCount = 0;
//先假设负数的个数更多,以负数开头
int postiveIndex = 0;
int pos = 1;
int neg = 0;
// Shifting all the postive numbers to the left
// 用一个循环,但凡我们找到了正数,
// 就swap到下个正数应该在的位置(positiveIndex)。
for (int i = 0; i < A.length; i++){
if(A[i] > 0){
swap(A, postiveIndex++, i);
postiveCount++;
}
}
//[1,2,3,4,-1,-2,-3]
// More positives
if (postiveCount > length / 2){
pos = 0;
neg = 1;
int left = 0;
int right = length - 1;
while (left < right) {
swap(A, left, right);
left++;
right--;
}
}
//[-1,-2,-3,1,2,3,4]
//[1,-2,-3,-1,2,3,4]
//[1,-2,3,-1,2,-3,4]
//done
while (pos < length && neg < length){
while(pos < length && A[pos] > 0){
pos+=2;
}
while(neg<length && A[neg] <= 0){
neg+=2;
}
if(neg >= length && pos>= length){
break;
}
swap(A, pos, neg);
}
}
private void swap (int[]A, int i, int j){
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
LeetCode 561. Array Partition I
我的solution:
Runtime: 16 ms, faster than 11.37% of Java online submissions for Array Partition I.
Memory Usage: 41.6 MB, less than 96.43% of Java online submissions for Array Partition I.
总结概括
自己对于这道题难度打分:2/10,题目陈述不够清晰
这道题花费的时间:15min
本题提交了几次:1
一句话评价本题:easy,但是我的解法没有必要。只需要return一个value,我却习惯性地用双指针把array都sort好了。anyway,not a bad practice。
题目分析
描述题意:看题
第一思路是什么:sort
思路过程:把array排序一遍,然后“跳着”取数。
正确思路以及花费时间:sort完跳着一个个把数字加起来,return
代码实现
花费时间:15min
静态查错花费多久时间:1min
代码的可读性:不好,一点也不好
最终评测
你自己设置的数据,以及你想要卡掉的点:ok
你的数据是否符合最终的期望:不好,白做很多功。这个题目很简单。
class Solution{
public int arrayPairSum(int[] nums) {
if (nums == null || nums.length == 0){
return 0;
}
if(nums.length < 3){
return Math.min(nums[0], nums[1]);
}
Arrays.sort(nums);
int slow = 1;
int fast = 2;
while (slow < fast && fast < nums.length){
swap(nums, slow, fast);
slow++;
fast+=2;
}
int end = nums.length - 1;
while (slow<end){
swap(nums, slow, end);
slow++;
end--;
}
int sum = 0;
for (int i = 0; i < nums.length / 2; i++){
sum += nums[i];
}
return sum;
}
private void swap (int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] =temp;
}
}
别人的:
public class Solution {
public int arrayPairSum(int[] nums) {
Arrays.sort(nums);
int result = 0;
for (int i = 0; i < nums.length; i += 2) {
result += nums[i];
}
return result;
}
}
75. Sort Colors
简单粗暴:给定一个由0,1,2组成的数组,in-place排序。更过分一点:双指针,one pass排序。
i相等于一个活动的指针,pl是为了指向左边起的1的位置,因为i遇到0的时候要和前面的1换位置。i遇到1的时候,啥也不做,继续往下走。i遇到2的时候,和pr换位置,因为pr是从右边开始的。
class Solution {
public void sortColors(int[] nums) {
if (nums == null || nums.length == 0){
return;
}
int pl = 0;
int pr = nums.length - 1;
int i = 0;
while (i <= pr){
if (nums[i] == 0){
swap(nums, i, pl);
i++;
pl++;
} else if (nums[i] == 2){
swap(nums, i, pr);
pr--;
} else {
i++;
}
}
}
private void swap (int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
3. Longest Substring Without Repeating Characters
最开始我是用brute force的,不出意料地超时。(其实写对了,但是oj无脑判超时,悲伤)。
class Solution {
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0){
return 0;
}
int longest = 0;
for (int i = 0; i < s.length(); i++){
for (int j = i + 1; j <= s.length(); j++){
if (noRepeat(s.substring(i, j))){
longest = Math.max(longest, j - i);
}
}
}
return longest;
}
private boolean noRepeat (String s){
Set <Character> set = new HashSet <>();
for (int i = 0 ; i < s.length(); i++){
if (set.contains(s.charAt(i))){
return false;
} else {
set.add(s.charAt(i));
}
}
return true;
}
}
后来参考大神的想法:
用一个hashset和两个指针。Set用于记忆一段substring。
慢指针指向一段无重复substring(就是这个set)的头,快指针一直遍历这个string,直到找到和慢指针相同的字母。
找到和慢指针一样的字母之后,应该在set中删除慢指针元素,这个时候我们的set才会依然保持“无重复字母+substring”这个性质。更新慢指针,现在慢指针指向现在substring的第一个字母啦;)
class Solution {
public int lengthOfLongestSubstring(String s) {
int i = 0;
int j = 0;
int max = 0;
Set <Character> set = new HashSet<>();
while (j < s.length()){
if (!set.contains(s.charAt(j))){
set.add(s.charAt(j));
j++;
max = Math.max(max, set.size());
} else {
set.remove(s.charAt(i));
i++;
}
}
return max;
}
}