和为s 的两个数
输入一个递增排序的数组和一个数字s,在数组中查找两个数,得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。
举例说明
例如输入数组{1 、2 、4、7 、11 、15 }和数字15. 由于4+ 11 = 15 ,因此输出4 和11 。
暴力破解当然可以,但是考虑到数组有序为递增的,所以要用一下这个条件,更好。
public static List<Integer> findNumbersWithSum(int[] data, int sum) {
List<Integer> result = new ArrayList<>(2);
if (data == null || data.length < 2) {
return result;
}
// 定义左右指针
int right = data.length - 1;
int left = 0;
long curSum; // 统计和,取long是防止结果溢出
while (left < right) {
curSum = data[left] + data[right];
// 相等即命中
if (curSum == sum) {
result.add(data[left]);
result.add(data[right]);
break;
} else if (curSum < sum) {
// 如果< sum ,那就使和大一点,移动左边的指针,使其和变大
left++;
} else {
// 反之,右边的指针往左移,使和变小
right--;
}
}
return result;
}
输入一个正数s,打印出所有和为s 的连续正数序列(至少两个数)
例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打出3 个连续序列1~5、4~6 和7~8。
// 输入一个正数s,打印出所有和为s 的连续正数序列(至少两个数)。
public static List<List<Integer>> findContinuousSequence(int sum) {
List<List<Integer>> result = new ArrayList<>();
if (sum < 3) {
return result;
}
int small = 1;
int big = 2;
int middle = (1 + sum) / 2;
int curSum = small + big;
// 用middle 来控制外层循环,很巧妙
// 针对这种类型的题,可以当成公式
while (small < middle) {
if (curSum == sum) {
List<Integer> list = new ArrayList<>(2); // 节省空间,内部有扩容机制
for (int i = small; i <= big; i++) {
list.add(i);
}
result.add(list);
}
while (curSum > sum && small < middle) {
// 如果curSum > sum 那么我们就去掉一点看看是否可以
curSum -= small;
small++;
if (curSum == sum) {
List<Integer> list = new ArrayList<>(2);
for (int i = small; i <= big; i++) {
list.add(i);
}
result.add(list);
}
}
// curSum < sum 那就big++ 来使序列的值扩大
// small < middle 这个条件使循环结束
big++;
curSum += big;
}
return result;
}
左旋转字符串
比如输入字符串”abcdefg”和数字2,该函数将返回左旋转2 位得到的结”cdefgab”。
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。
public static char[] leftRotateString(char[] data, int n) {
if (data == null || n < 0 || n > data.length) {
return data;
}
reverse(data, 0, data.length - 1);
reverse(data, 0, data.length - n - 1);
reverse(data, data.length - n, data.length - 1);
return data;
}
public static void reverse(char[] data, int start, int end) {
if (data == null || data.length < 1 || start < 0 || end > data.length || start > end) {
return;
}
// 这样反转,效率提高一半
// start 与 end 位交换
while (start < end) {
char tmp = data[start];
data[start] = data[end];
data[end] = tmp;
start++;
end--;
}
}
高效移动数组
[0,1,0,3,12] -> [1,3,12,0,0]
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
public void moveZeroes(int[] nums) {
int i = 0;
for(int j = 0; j < nums.length; j++){
if(nums[j] != 0){
if (i != j)
nums[i] = nums[j];
i++;
}
}
for(; i < nums.length; i++){
nums[i] = 0;
}
}