面試題03.數組中重複的數字
安安思路1:兩次遍歷
時間複雜度O(n^2)
//用C語言寫出現了超時的問題
int findRepeatNumber(int* nums, int numsSize){
for(int i = 0; i < numsSize; i++){
for(int j = i+1; j < numsSize;j++){
//printf("nums[%d]=%d, nums[%d]=%d\n", i, nums[i], j, nums[j]);
if(nums[i] == nums[j]){
return nums[i];
}
}
}
return 0;
}
//java
class Solution {
public int findRepeatNumber(int[] nums) {
for(int i = 0; i < nums.length; i++){
for(int j = i+1; j < nums.length;j++){
if(nums[i] == nums[j]){
return nums[i];
}
}
}
return 0;
}
}
安安思路2:哈希表(字典存儲)
時間複雜度O(n)
#python
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
dict1 = {}
for i in range(len(nums)):
if nums[i] in dict1:
dict1[nums[i]] += 1
else:
dict1[nums[i]] = 1
#print(dict1)
for (k,v) in dict1.items():
if v > 1:
return k;
安安思路2改進:哈希表(字典存儲)
時間複雜度O(n)
# python
# 由於題目要求任意一個重複的,所以遇到重複的直接返回就可以了
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
dict1 = {}
for i in range(len(nums)):
if nums[i] in dict1:
return nums[i]
else:
dict1[nums[i]] = 1
#print(dict1)
官方題解:遍歷數組
//java
class Solution {
public int findRepeatNumber(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
int repeat = -1;
for (int num : nums) {
if (!set.add(num)) {
repeat = num;
break;
}
}
return repeat;
}
}
面試題04.二維數組中的查找
安安思路:暴力法
//java
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[i].length; j++){
//System.out.println(matrix[i][j]+" ");
if(matrix[i][j] == target){
return true;
}
}
}
//System.out.println();
return false;
}
}
//java
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
for(int[] arr:matrix){ //int[]二維數組中元素的類型, arr迭代變量, matrix二維組的名稱
for(int i:arr){ //int,一維數組中元素的類型,i,迭代變量,arr,一維數組的名稱
//System.out.print(i+"\t");
if(i == target){
return true;
}
}
}
return false;
}
}
//java
//如果該行某值大於target,直接查找下一行
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[i].length; j++){
if(matrix[i][j] == target){
return true;
}else if(matrix[i][j] > target){
continue;
}
}
}
//System.out.println();
return false;
}
}
官方題解:線性查找
//java
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix.length == 0 ){ //[]
return false;
}
int i = 0;
int j = matrix[i].length-1;
while(i < matrix.length && j >= 0 ){
//System.out.println(matrix[i][j]);
if(matrix[i][j] == target){
return true;
}else if(matrix[i][j] > target){
j--;
}else{
i++;
}
}
//System.out.println();
return false;
}
}
面試題21.調整數組順序使奇數位於偶數前面
安安思路:雙指針
//java 2020.3.28 anan 雙指針
class Solution {
public int[] exchange(int[] nums) {
int left = 0;
int right = nums.length-1;
while(left < right){
while(left< right && nums[left] % 2 != 0){ //遇到奇數了, 加加
left++;
}
while(left < right && nums[right] % 2 == 0){
right--;
}
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
}
return nums;
}
}
同類型問題擴展 解耦 lambda表達式
Lambda 表達式,也可稱爲閉包,它是推動 Java 8 發佈的最重要新特性。
Lambda 允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中)。
使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。
//java
class Solution {
public int[] exchange(int[] nums) {
return mainPart(nums, isOdd); //只需修改此處的函數即可實現
}
public int[] mainPart(int[] nums, JudgeFunction judgeFunction){
int left = 0;
int right = nums.length-1;
while(left < right){
while(left< right && judgeFunction.judge(nums[left])) left++;
while(left < right && (!judgeFunction.judge(nums[right]))) right--;
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
}
return nums;
}
interface JudgeFunction {
boolean judge(int num);
}
JudgeFunction isOdd = (int num) -> (num%2)!=0; //判斷奇偶性 //要求奇數位於偶數前面
JudgeFunction isNegative = (int num) -> (num < 0); //負數位於非負數前面
JudgeFunction isThreeTimes = (int num) -> (num%3 == 0); //能被3整除的位於不能被3正常的前面
}
面試題29.順時針打印矩陣(54)
安安思路:遞歸
//java anan 2020.3.28
class Solution {
int[] res;
int index;
boolean[][] visited;
int rows;
int cols;
int[][] matrix;
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
//初始化
rows = matrix.length;
cols = matrix[0].length;
res = new int[rows*cols];
index = -1;
visited = new boolean[rows][cols];
this.matrix = matrix;
move(0, 0);
return res;
}
public void move(int x, int y){
if((x >= 0 && x<= rows-1 && y >= 0 && y <= cols-1 && visited[x][y] == false) == false) return ;
visited[x][y] = true;
res[++index] = matrix[x][y];
if(y < cols/2){ //位於矩陣的左半部分
move(x, y-1); //左
move(x-1, y); //上
move(x, y+1); //右
move(x+1, y); //下
}else{ //位於矩陣的右半部分
move(x, y+1); //右
move(x+1, y); //下
move(x, y-1); //左
move(x-1, y); //上
}
}
}
官方解法1:模擬
//java
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List ans = new ArrayList();
if (matrix.length == 0) return ans;
int R = matrix.length, C = matrix[0].length;
boolean[][] seen = new boolean[R][C];
int[] dr = {0, 1, 0, -1};
int[] dc = {1, 0, -1, 0};
int r = 0, c = 0, di = 0;
for (int i = 0; i < R * C; i++) {
ans.add(matrix[r][c]);
seen[r][c] = true;
int cr = r + dr[di];
int cc = c + dc[di];
if (0 <= cr && cr < R && 0 <= cc && cc < C && !seen[cr][cc]){
r = cr;
c = cc;
} else {
di = (di + 1) % 4;
r += dr[di];
c += dc[di];
}
}
return ans;
}
}
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
官方解法2:按層模擬(劍指offer)
//java
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
int rows = matrix.length;
int cols = matrix[0].length;
int x1 = 0, y1 = 0; //左上角
int x2 = rows-1, y2 = cols-1; //右下角
int[] res = new int[rows*cols];
int index = -1;
while(index < rows*cols && x1<=x2 && y1<=y2){
for(int x=x1, y=y1; y <= y2; y++) res[++index] = matrix[x][y]; //右 算上右上角
for(int x=x1+1, y=y2; x <= x2; x++) res[++index] = matrix[x][y]; //下 算上右下角
if(x1 < x2 && y1 < y2){
for(int x=x2, y=y2-1; y > y1; y--) res[++index] = matrix[x][y]; //左 不算左下角
for(int x=x2, y=y1; x > x1; x--) res[++index] = matrix[x][y]; //上 不算左上角
}
x1++; y1++;
x2--; y2--;
System.out.println(x1+ " " + y1 + " " + x2 + " " + y2);
}
return res;
}
}
面試題40.最小的k個數
安安 O(nlogn)
//java
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
Arrays.sort(arr);
return Arrays.copyOfRange(arr, 0, k);
}
}
//[3,2,1,1] k=2 輸出:[1,1]
官方1:堆O(nlogK) (劍指offer)
(leetcode官方)我們用一個大根堆實時維護數組的前 k 小值。首先將前 k 個數插入大根堆中,隨後從第 k+1個數開始遍歷,如果當前遍歷到的數比大根堆的堆頂的數要小,就把堆頂的數彈出,再插入當前遍歷到的數。最後將大根堆裏的數存入數組返回即可。
//java anan 2020.3.30
//獲取最大的k個值 小根堆
//獲取最小的k個值 大根堆
class Solution {
public int[] getLeastNumbers(int[] arr, int k){
if(k == 0) return new int[0];
Queue<Integer> q = new PriorityQueue<>(k, new Comparator<Integer>() {
public int compare(Integer i1, Integer i2) {
return i2-i1;
}
});
for (int i = 0; i < k; i++) q.add(arr[i]);
for (int i = k; i < arr.length; i++) {
if(arr[i] < q.peek()){
q.poll();
q.add(arr[i]);
}
}
Object[] resTmp = q.toArray();
int[] res = new int[k];
for(int i = 0; i < k; i++){
res[i] = (Integer)resTmp[i];
}
// 將堆中的元素存入數組 其他同學的寫法
// int[] res = new int[heap.size()];
// int j = 0;
// for (int e : heap) {
// res[j++] = e;
// }
//PriorityQueue的iterator()不保證以任何特定順序遍歷隊列元素。但是我們也不需要順序,所以直接遍歷就可以了
return res;
}
}
//[3,2,1,1] k=2 輸出:[1,1]
作者:aanmunyeon
鏈接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/topkwen-ti-javada-gen-dui-shi-xian-by-aanmunyeon/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
官方2:快速選擇思想O(n) (劍指offer) 必須修改數組
//java
class Solution {
public int[] getLeastNumbers(int[] arr, int k){ //先獲取最大的k個值 小根堆
if(k == 0) return new int[0];
if(k == arr.length) return arr;
partitionArray(arr, k, 0, arr.length-1);
int[] res = new int[k];
res = Arrays.copyOf(arr, k);
return res;
}
public static void partitionArray(int[] arr, int k, int low, int high){
int m = partition(arr, low, high);
if(m == k){
return ;
}else if(m < k){
partitionArray(arr, k, m+1, high);
}else{
partitionArray(arr, k, low, m-1);
}
}
//快排的partition函數
public static int partition(int[] array, int low, int high){
int base = array[low];
int i = low;
int j = high;
while(i < j){
while(array[j] > base && i < j) j--;
while(array[i] <= base && i < j) i++;
swap(array, i, j);
//System.out.println(i + " " + j + " " + Arrays.toString(array));
}
swap(array, low, j);
//System.out.println(i + " " + j + " " + Arrays.toString(array));
return j;
}
public static void swap(int[] a, int i, int j){
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
//[3,2,1,1] k=2 輸出:[1,1]
面試題39.數組中出現次數超過一半的數字(169)
法1:哈希表
法2:數組排序法(劍指offer) O(n)
直接調用函數排序的時間複雜度爲O(nlogn)
利用面試題40的苦熬蘇選擇思想 時間複雜度可變爲O(n)
法3:摩爾投票法(劍指offer) O(n)
//java anan 2020.3.30
class Solution {
public int majorityElement(int[] nums) {
//統計每個數字出現的次數
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);
}
}
//System.out.println(map);
//找到出現次數最多的元素
Set<Integer> set = map.keySet();
int max = Integer.MIN_VALUE;
for(int i: set){
if(map.get(i) > nums.length/2)
return i;
}
return 0;
}
}
面試題42.連續子數組的最大和(53)
法1:DP O(n) (劍指offer)
法2:分治法 O(nlogn)
分治法思路之前看不明白
這篇博客講的挺清楚的 看懂啦 開心
見該博客
//java anan模仿着寫的
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
if(n == 0) return 0;
return partition(nums, 0, n-1);
}
public static int partition(int[] nums, int left, int right){
if(left == right) return nums[left];
int mid = (left+right)/2;
//左邊序列和右邊序列的最大子序和
int maxSumLeft = partition(nums, left,mid);
int maxSumRight = partition(nums, mid+1, right);
//包含左邊序列最後一個元素的最大序列和
int maxSumLeftBorder = nums[mid];
int sumLeftBorder = nums[mid];
for(int i = mid-1; i >= left; i--){
sumLeftBorder += nums[i];
maxSumLeftBorder = Math.max(maxSumLeftBorder, sumLeftBorder);
}
//包含右邊序列第一個元素的最大序列和
int maxSumRightBorder = nums[mid+1];
int sumRightBorder = nums[mid+1];
for(int i = mid+2; i <= right; i++){
sumRightBorder += nums[i];
maxSumRightBorder = Math.max(maxSumRightBorder, sumRightBorder);
}
int maxSumCross = maxSumLeftBorder+maxSumRightBorder;
int maxOfThree = ((maxSumLeft > maxSumRight) ? maxSumLeft : maxSumRight) > maxSumCross ? ((maxSumLeft > maxSumRight) ? maxSumLeft : maxSumRight) : maxSumCross;
//System.out.println(maxSumLeft + " " + maxSumRight + " " + maxSumCross + " " + maxOfThree);
return maxOfThree;
}
}
面試題47.禮物的最大價值(矩陣)(64)
法1:DP二維
//java anan 2020.3.30
class Solution {
public int maxValue(int[][] grid) {
if(grid.length == 0) return 0;
int rows = grid.length;
int cols = grid[0].length;
int[][] dp = new int[rows][cols];
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
if(i == 0 && j == 0) dp[i][j] = grid[0][0];
else if(i == 0) dp[i][j] = dp[i][j-1]+grid[i][j];
else if(j == 0) dp[i][j] = dp[i-1][j]+grid[i][j];
else dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1])+grid[i][j];
}
}
return dp[rows-1][cols-1];
}
}
//java 參考自己之前寫的代碼進行了代碼改進
class Solution {
public int maxValue(int[][] grid) {
if(grid.length == 0) return 0;
int rows = grid.length;
int cols = grid[0].length;
int[][] dp = new int[rows][cols];
dp[0][0] = grid[0][0];
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
if(i != 0 || j != 0){
dp[i][j] = Math.max( (i >=1 ? dp[i-1][j] : Integer.MIN_VALUE), (j >= 1 ? dp[i][j-1] : Integer.MIN_VALUE ) ) + grid[i][j];
}
}
}
return dp[rows-1][cols-1];
}
}
法2:DP(一維)
//java 空間優化
class Solution {
public int maxValue(int[][] grid) {
if(grid.length == 0) return 0;
int rows = grid.length;
int cols = grid[0].length;
int[] dp = new int[cols];
dp[0] = grid[0][0];
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
if(i != 0 || j != 0){
dp[j] = Math.max( (i >=1 ? dp[j] : Integer.MIN_VALUE), (j >= 1 ? dp[j-1] : Integer.MIN_VALUE ) ) + grid[i][j];
}
}
}
return dp[cols-1];
}
}
法3:DP(不開闢新數組)
//java 不開闢數組空間 在原數組上操作
class Solution {
public int maxValue(int[][] grid) {
if(grid.length == 0) return 0;
int rows = grid.length;
int cols = grid[0].length;
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
if(i != 0 || j != 0){
grid[i][j] = Math.max( (i >=1 ? grid[i-1][j] : Integer.MIN_VALUE), (j >= 1 ? grid[i][j-1] : Integer.MIN_VALUE )) + grid[i][j];
}
}
}
return grid[rows-1][cols-1];
}
}