19、顺时针打印矩阵
简单来说,就是不断地收缩矩阵的边界
定义四个变量代表范围,up、down、left、right
向右走存入整行的值,当存入后,该行再也不会被遍历,代表上边界的 up 加一,同时判断是否和代表下边界的 down 交错
向下走存入整列的值,当存入后,该列再也不会被遍历,代表右边界的 right 减一,同时判断是否和代表左边界的 left 交错
向左走存入整行的值,当存入后,该行再也不会被遍历,代表下边界的 down 减一,同时判断是否和代表上边界的 up 交错
向上走存入整列的值,当存入后,该列再也不会被遍历,代表左边界的 left 加一,同时判断是否和代表右边界的 right 交错
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
return list;
}
int up = 0;
int down = matrix.length-1;
int left = 0;
int right = matrix[0].length-1;
while(true){
// 最上面一行
for(int col=left;col<=right;col++){
list.add(matrix[up][col]);
}
// 向下逼近
up++;
// 判断是否越界
if(up > down){
break;
}
// 最右边一行
for(int row=up;row<=down;row++){
list.add(matrix[row][right]);
}
// 向左逼近
right--;
// 判断是否越界
if(left > right){
break;
}
// 最下面一行
for(int col=right;col>=left;col--){
list.add(matrix[down][col]);
}
// 向上逼近
down--;
// 判断是否越界
if(up > down){
break;
}
// 最左边一行
for(int row=down;row>=up;row--){
list.add(matrix[row][left]);
}
// 向右逼近
left++;
// 判断是否越界
if(left > right){
break;
}
}
return list;
}
}
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
int l = 0, r = matrix[0].length - 1, t = 0, b = matrix.length - 1, x = 0;
int[] res = new int[(r + 1) * (b + 1)];
while(true) {
for(int i = l; i <= r; i++) res[x++] = matrix[t][i]; // left to right.
if(++t > b) break;
for(int i = t; i <= b; i++) res[x++] = matrix[i][r]; // top to bottom.
if(l > --r) break;
for(int i = r; i >= l; i--) res[x++] = matrix[b][i]; // right to left.
if(t > --b) break;
for(int i = b; i >= t; i--) res[x++] = matrix[i][l]; // bottom to top.
if(++l > r) break;
}
return res;
}
}
python
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
res = []
while matrix:
res += matrix.pop(0)
matrix = list(zip(*matrix))[::-1]
return res
32、把数组排成最小的数
要注意,java中字符串也可以用compare to作比较
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用StringBuilder
class Solution {
public String minNumber(int[] nums) {
String[] strs = new String[nums.length];
for(int i = 0; i < nums.length; i++)
strs[i] = String.valueOf(nums[i]);
Arrays.sort(strs, (x, y) -> (x + y).compareTo(y + x));
StringBuilder res = new StringBuilder();
for(String s : strs)
res.append(s);
return res.toString();
}
}
37、数字在排序数组中出现的次数
自己的写法 没通过测试
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int low=0;
int high=array.length-1;
int mid = low + (high - low) / 2;
if(array[low]>k || array[high]<k) return 0;
while( !(array[low]== k && array[high]== k)){
if(array[mid]>k) high = mid ;
if(array[mid]<k) low = mid ;
if(array[mid]==k && array[low]!=k) low += 1 ;
if(array[mid]==k && array[high]!=k) high -= 1 ;
mid = low + (high - low) / 2;
}
return high-low+1;
}
}
官方的二分写法
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int length = array.length;
if(length == 0){
return 0;
} //长度为0直接返回0
int firstK = getFirstK(array, k, 0, length-1);
int lastK = getLastK(array, k, 0, length-1);
if(firstK != -1 && lastK != -1){
return lastK - firstK + 1;
}
return 0;
}
//递归写法 找到第一个K位置
private int getFirstK(int [] array , int k, int start, int end){
if(start > end){
return -1;
}
int mid = (start + end) >> 1;
if(array[mid] > k){
return getFirstK(array, k, start, mid-1);//中间大于K,end=mid-1,找左段
}else if (array[mid] < k){
return getFirstK(array, k, mid+1, end);//中间小于K,start=mid+1,找右段
}else if(mid-1 >=0 && array[mid-1] == k){
return getFirstK(array, k, start, mid-1);//中间在1右边,值为K,找左段
}else{
return mid;
}
}
//循环写法 找到最后一个K位置
private int getLastK(int [] array , int k, int start, int end){
int length = array.length;
int mid = (start + end) >> 1;
while(start <= end){
if(array[mid] > k){
end = mid-1;//中间大于K,end=mid-1,找左段
}else if(array[mid] < k){
start = mid+1;//中间小于K,start=mid+1,找右段
}else if(mid+1 < length && array[mid+1] == k){//中间在最大值左边,值为K,找右段
start = mid+1;
}else{
return mid;
}
mid = (start + end) >> 1;
}
return -1;
}
}
35、数组中的逆序对
归并排序
public class Solution {
// 归并排序的思路来做这道题目以实现o(nlogn)的复杂度。
//归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。
//java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。
//从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。
//而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。
private int cnt;
public int InversePairs(int [] array) {
//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
int[] temp=new int[array.length];
MergeSort(array, 0, array.length-1,temp);
return cnt;
}
private void MergeSort(int[] array, int start, int end, int[]temp){
if(start>=end) return;
int mid = (start+end)/2;
MergeSort(array, start, mid, temp);//左边 递归
MergeSort(array, mid+1, end, temp);//右边 递归
MergeOne(array, start, mid, end,temp);
}
private void MergeOne(int[] array, int start, int mid, int end,int[] temp){
int k=0,i=start,j=mid+1;
while(i<=mid && j<= end){//当左边起始点小于中间点,右边起始点小于结束点
//如果前面的元素小于后面的不能构成逆序对
if(array[i] <= array[j])
temp[k++] = array[i++];
//如果前面的元素大于后面的,那么在前面元素之后的元素都能和后面的元素构成逆序对
else{
temp[k++] = array[j++];
//增加的一行代码,用来统计逆序对个数
cnt = (cnt + (mid-i+1))%1000000007;
}
}
//将左边剩余元素填充进temp中
while(i<= mid)
temp[k++] = array[i++];
//将右序列剩余元素填充进temp中
while(j<=end)
temp[k++] = array[j++];
k=0;
//将temp中的元素全部拷贝到原数组中
while(start<=end){
array[start++] = temp[k++];
}
}
}
归并排序的基础上加一行代码
class Solution {
//全局变量
private int count;
public int reversePairs(int[] nums) {
count = 0;
merge(nums,0,nums.length-1);
return count;
}
public void merge (int[] nums, int left, int right) {
if (left < right) {
int mid = left + ((right - left) >> 1);
merge(nums,left,mid);
merge(nums,mid+1,right);
mergeSort(nums,left,mid,right);
}
}
public void mergeSort(int[] nums, int left, int mid, int right) {
int[] temparr = new int[right-left+1];
int index = 0;
int temp1 = left, temp2 = mid+1;
while (temp1 <= mid && temp2 <= right) {
if (nums[temp1] <= nums[temp2]) {
temparr[index++] = nums[temp1++];
} else {
//增加的一行代码,用来统计逆序对个数
count += (mid - temp1 + 1);
temparr[index++] = nums[temp2++];
}
}
if (temp1 <= mid) System.arraycopy(nums,temp1,temparr,index,mid-temp1+1);
if (temp2 <= right) System.arraycopy(nums,temp2,temparr,index,right-temp2+1);
System.arraycopy(temparr,0,nums,left,right-left+1);
}
}