假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回-1。你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
备注:
做了好久,感觉代码写的也不是很好。
class Solution {
public int search(int[] nums, int target) {
if(nums == null || nums.length == 0)
return -1;
int ans = searchCore(nums,0,nums.length -1 ,target);
return ans;
}
public int searchCore(int[] arr,int low,int high,int target){
int mid;
int ans = -1;
mid = (low + high) >> 1;
if(low > high){
return -1;
}
if(arr[mid] == target){
return mid;
}
//左半边有序 且target在这个范围之内
else if(arr[low] < arr[mid] && target < arr[mid] && target >= arr[low]){
ans = searchCore(arr,low,mid-1,target);
}
//右半边有序 且target在这个范围之内
else if(arr[mid] < arr[high] && target <= arr[high] && target > arr[mid]){
ans = searchCore(arr,mid+1,high,target);
}
if(ans == -1){
ans = searchCore(arr,low,mid-1,target);
}
return ans!=-1? ans : searchCore(arr,mid+1,high,target);
}
}
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] ans = new int[]{-1,-1};
//讨论区看到的解法,可以不用写两个二分
int start = binarySearch(nums,target - 0.5);
int stop = binarySearch(nums,target + 0.5);
if(stop == -1 || nums[stop] != target){
return ans;
}
ans[0] = start + 1;
ans[1] = stop;
return ans;
}
public int binarySearch(int [] nums ,double k){
int low = 0;
int high = nums.length -1;
while(low <= high){ // = 是必须的[5 7 7 8 8 10] t = 8
int mid = (low + high) >> 1;
if(nums[mid] < k)
low = mid + 1;
else
high = mid -1;
}
return high;
}
}
给定 n 个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水
抄的讨论区的代码,还有另一种思路是找出最高点分别从两边往最高点遍历:如果下一个数比当前数小,说明可以接到水。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
class Solution {
public int trap(int[] height) {
if(height == null || height.length == 0)
return 0;
int n = height.length;
int left[] = new int[n];
int right[] = new int[n];
// left[i]表示i左边的最大值,right[i]表示i右边的最大值
for(int i = 1;i<n;i++){
left[i] = Math.max(left[i-1],height[i-1]);
right[n - i - 1] = Math.max(right[n-i],height[n-i]);
}
int ans = 0;
int level = 0;
//只要从1..n-2
for(int i=1;i<n-1;i++){
level = Math.min(left[i],right[i]);
ans += level > height[i] ? level - height[i] : 0;
}
return ans;
}
}
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
public List<List<Integer>> permute(int[] nums) {
if (nums == null || nums.length == 0)
return Collections.EMPTY_LIST;
List<List<Integer>> ret = new ArrayList<List<Integer>>();
List<Integer> ans = new ArrayList<>();
collect(ret, ans, nums);
return ret;
}
public void collect(List<List<Integer>> ret, List<Integer> ans, int[] nums) {
if (ans.size() == nums.length) {
ret.add(new ArrayList<Integer>(ans));
return;
}
for (int i = 0; i < nums.length; i++) {
// 保证没有重复的元素
if (ans.contains(Integer.valueOf(nums[i])))
continue;
ans.add(nums[i]);
collect(ret, ans, nums);
ans.remove(Integer.valueOf(nums[i]));
}
}
给定一个 n × n 的二维矩阵表示一个图像。将图像顺时针旋转 90 度。
说明:
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
示例 :
给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
备注:
参考CodeInterView,交换的过程有点复杂,不是很清楚
class Solution {
public void rotate(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return;
}
int tr = 0;
int tc = 0;
int dr = matrix.length - 1;
int dc = matrix[0].length - 1;
while (tr < dr) {
rotateCore(matrix, tr++, tc++, dr--, dc--);
}
}
public void rotateCore(int[][] m, int tr, int tc, int dr, int dc) {
int times = dc - tc;
int tmp = 0;
for (int i = 0; i < times; i++) {
tmp = m[tr][tc + i];
m[tr][tc + i] = m[dr - i][tc];
m[dr - i][tc] = m[dr][dc - i];
m[dr][dc - i] = m[tr + i][dc];
m[tr + i][dc] = tmp;
}
}
}
讨论区解法:
旋转前:1 2 3 / 4 5 6 / 7 8 9
旋转后:7 4 1 / 8 5 2 / 9 6 3
可以看到旋转后第一行的元素为原来数组从下往上数每行的第一个元素,所以设 i 为行号,j 为列号,n 为行数。 则若将二维数组看成一维数组,则matrix[i][j]转换后里面的元素的下标为 n * (n - j - 1) + i
public void rotate(int[][] matrix) {
int n = matrix.length;
Map<Integer, Integer> map = new HashMap<>();
//将二维数组中的元素值放入哈希表,key为将二维数组看成一维数组时的数组下标(即0, 1, 2, 3 ...)
for (int i = 0, k = 0; i < matrix.length; i++){
for (int j = 0; j < matrix[i].length; j++, k++){
map.put(k, matrix[i][j]);
}
}
//将二维数组每个元素的值置换为运算后的看作一维数组时的数组下标
for (int i = 0; i < matrix.length; i++){
for (int j = 0; j < matrix[i].length; j++){
matrix[i][j] = n * (n - j - 1) + i;
}
}
//再用置换后的二维数组的元素值作为键,取出哈希表中的值,并将此值放入二维数组
for (int i = 0, k = 0; i < matrix.length; i++){
for (int j = 0; j < matrix[i].length; j++, k++){
matrix[i][j] = map.get(matrix[i][j]);
}
}
}