java數組算法題

1.給定一個排序數組,你需要在原地刪除重複出現的元素,使得每個元素只出現一次,返回移除後數組的新長度。不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。  
輸入[0,0,1,1,1,2,2,3,3,4],
函數應該返回新的長度 5, 並且原數組 nums 的前五個元素被修改爲 0, 1, 2, 3, 4。

思路解析:利用slow=0,fast=1,分別指向數組的第0,1號元素,if(他們相同時),{fast++},else{直到不同時,將slow的下一個元素替換爲fast的元素,slow++,fast++}

public static int removeDuplicates(int[] nums) {
	int slow = 0;
	for (int fast = 1; fast < nums.length; fast++) {
		if (nums[slow] != nums[fast]) {
			nums[slow + 1] = nums[fast];
			slow++;
		}
	}
	return slow + 1;
}

2.給定一個數組,將數組中的元素向右移動 個位置,其中 是非負數。

輸入: 
[1,2,3,4,5,6,7]
 和 k = 3
輸出: 
[5,6,7,1,2,3,4]

說明:
.儘可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。
.要求使用空間複雜度爲 O(1) 的原地算法。

思路解析:元素後移k次就行了,另一種是利用翻轉,任何數組翻轉3次即可,還有一種思路新奇

/**
     * 翻轉
     * 時間複雜度:O(n)
     * 空間複雜度:O(1)
     */
    public void rotate_2(int[] nums, int k) {
        int n = nums.length;
        k %= n;
        reverse(nums, 0, n - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, n - 1);
    }


    private void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int temp = nums[start];
            nums[start++] = nums[end];
            nums[end--] = temp;
        }
    }

    /**
     * 循環交換
     * 時間複雜度:O(n^2/k)
     * 空間複雜度:O(1)
     */
    public void rotate_3(int[] nums, int k) {
        int n = nums.length;
        k %= n;
        // 第一次交換完畢後,前 k 位數字位置正確,後 n-k 位數字中最後 k 位數字順序錯誤,繼續交換
        for (int start = 0; start < nums.length && k != 0; n -= k, start += k, k %= n) {
            for (int i = 0; i < k; i++) {
                swap(nums, start + i, nums.length - k + i);
            }
        }
    }

 

3.給定一個整數數組,判斷是否存在重複元素。

如果任何值在數組中出現至少兩次,函數返回 true。如果數組中每個元素都不相同,則返回 false。

輸入: [1,2,3,1]
輸出: true

輸入: [1,2,3,4]
輸出: false

思路解析:我做的是排序然後比較,還有set也比較容易想到,以及map的containKey方法

//Arrays.sort()
public boolean containsDuplicate(int[] nums) {
    Arrays.sort(nums);
    for(int i=0;i<nums.length-1;i++){
        if(nums[i]==nums[i+1]){
            return true;
        }
    }
    return false;
}
//if(!set.add())
public boolean containsDuplicate(int[] nums) {
	int len = nums.length;
	HashSet<Integer> set = new HashSet<>();
	for(int i=0;i<len;i++) {
		if(!set.add(nums[i]))return true;
	}
	return false;
}

//map.containsKey
public boolean containsDuplicate(int[] nums) {
    HashMap<Integer,Integer>map = new HashMap<>();
    for(int i=0;i<nums.length;i++){
        if(map.containsKey(nums[i])) return true;
        map.put(nums[i],0);
    }
    return false;
}
//Arrays.stream()
public boolean containsDuplicate(int[] nums) {
    Set<Integer> set = new HashSet<>();
    Arrays.stream(nums).forEach(set::add);
    return nums.length != set.size();
}

4.給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。

說明:你的算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?

輸入: [2,2,1]
輸出: 1

思路解析:運用" ^ "運算符,異或的運算方法是一個二進制運算: 1^1=0 ;0^0=0 ;1^0=1 ;0^1=1 

public int singleNumber(int[] nums) {
    int x=0;
    for(int i=0;i<nums.length;i++){
        x=x^nums[i];
    }
    return x;
}


5.給定兩個數組,編寫一個函數來計算它們的交集。

輸入: nums1 = [1,2,2,1], nums2 = [2,2]
輸出: [2,2]
輸入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
輸出: [4,9]

說明:
. 輸出結果中每個元素出現的次數,應與元素在兩個數組中出現的次數一致。
. 我們可以不考慮輸出結果的順序。

思路解析:排序後利用雙指針同時檢索兩個數組,取出相同的值

public int[] intersect(int[] nums1, int[] nums2) {
	Arrays.sort(nums1);
	Arrays.sort(nums2);
	List<Integer> list = new ArrayList<>();
	for (int i = 0, j = 0; i < nums1.length && j < nums2.length; ) {
		if (nums1[i] < nums2[j]) {
			i++;
		} else if (nums1[i] > nums2[j]) {
			j++;
		} else {
			list.add(nums1[i]);
			i++;
			j++;
		}
	}
	int[] res = new int[list.size()];
	for (int i = 0; i < list.size(); i++) {
		res[i] = list.get(i);
	}
	return res;
}

 

6.給定一個由整數組成的非空數組所表示的非負整數,在該數的基礎上加一。最高位數字存放在數組的首位, 數組中每個元素只存儲一個數字。你可以假設除了整數 0 之外,這個整數不會以零開頭。

輸入: [1,2,3]
輸出: [1,2,4]
解釋: 輸入數組表示數字 123。

思路解析:如果是9,就相當於該位爲0,前一位加1,直到第一位判定是否需要擴容

public int[] plusOne(int[] digits) {
	int len = digits.length;
	for(int i=len-1;i>=0;i--){
		if(digits[i]+1<10){
			digits[i]++;
			return digits;
		}else{
			digits[i]=0;
		}
	}
	int[] res=new int[len+1];
	res[0]=1;
	return res;
}

 

7.給定一個數組 nums,編寫一個函數將所有 0 移動到數組的末尾,同時保持非零元素的相對順序。

輸入: 
[0,1,0,3,12]
輸出: 
[1,3,12,0,0]

說明:
. 必須在原數組上操作,不能拷貝額外的數組。
. 儘量減少操作次數。

思路解析:其他元素前移佔據0的位置,然後再來補0,還有一種就是利用雙指針交換後直接填充0,這裏的if(i!=j)是爲了防止找到0之前i,j相同

public void moveZeroes(int[] nums) {
	int i = 0, j = 0;
	while (j < nums.length) {
		if (nums[j] != 0) {
			nums[i++] = nums[j];
		}
		j++;
	}
	while (i < nums.length) nums[i++] = 0;
}
//
public void moveZeroes(int[] nums) {
	int j=0;
	for(int i=0;i<nums.length;i++){
		if(nums[i]!=0){
			nums[j]=nums[i];
			if(i!=j) nums[i]=0;
			j++;
		}
	}
}

 

8.給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那兩個整數,並返回他們的數組下標。

你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個數組中同樣的元素。

給定 nums = [2, 7, 11, 15], target = 9

因爲 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

思路解析:雙for暴力破解,最優解是一遍哈希表

public int[] twoSum(int[] nums, int target) {
	for(int i=0;i<nums.length-1;i++){
		for(int j=i+1;j<nums.length;j++){
			if(nums[i]+nums[j]==target){
				int[] a=new int[2];
				a[0]=i;
				a[1]=j;
				return a;
			}
		}
	}
	return null;
}
//優解
public int[] twoSum(int[] nums, int target) {
	Map<Integer,Integer> map=new HashMap<>();
	for(int i=0;i<nums.length;i++){
		int diff=target-nums[i];
		if(map.containsKey(diff)){
			return new int[] {map.get(diff),i};
		}
		map.put(nums[i],i);
	}
	return null;
}

 

9.判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。

  1. 數字 1-9 在每一行只能出現一次。
  2. 數字 1-9 在每一列只能出現一次。
  3. 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。

上圖是一個部分填充的有效的數獨。

數獨部分空格內已填入了數字,空白格用 '.' 表示。

輸入:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
輸出: true

輸入:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
輸出: false

解釋: 除了第一行的第一個數字從 5 改爲 8 以外,空格內其他數字均與 示例1 相同。
但由於位於左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。

說明:
. 一個有效的數獨(部分已被填充)不一定是可解的。
. 只需要根據以上規則,驗證已經填入的數字是否有效即可。
. 給定數獨序列只包含數字 1-9 和字符 '.' 。
. 給定數獨永遠是 9x9 形式的。

思路解析:用的boolean數組,但卻像是map的思想,num作爲每行的元素值,再用3個數組分別行,列與3x3的情況,boolean[9][10]長度爲10因爲不用0,當然這種方式不好想到。下面的暴力破解法寫的比較優雅,也很好理解,k=i+1;總是從下一行開始與當前元素比較

public boolean isValidSudoku(char[][] board) {
       // 記錄某行,某位數字是否已經被擺放
	boolean[][] row = new boolean[9][10];
        // 記錄某列,某位數字是否已經被擺放
	boolean[][] col = new boolean[9][10];
        // 記錄某 3x3 宮格內,某位數字是否已經被擺放
	boolean[][] block = new boolean[9][10];
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (board[i][j] != '.') {
				int num = board[i][j] - '0';
				if (row[i][num] || col[j][num] || block[i / 3 * 3 + j / 3][num]) {
					return false;
				} else {
					row[i][num] = true;
					col[j][num] = true;
					block[i / 3 * 3 + j / 3][num] = true;
				}
			}
		}
	}
	return true;
}
//暴力破解
public static boolean isValidSudoku(char[][] board) {
	for(int i = 0; i < 9; i++){
		for(int j = 0; j < 9; j++){
			if(board[i][j] == '.')continue;
			for(int k = 8; k > j; k--){
				if(board[i][j] == board[i][k])
					return false;
			}
			for(int k = 8; k > i; k--){
				if(board[i][j] == board[k][j])
					return false;
			}
			for(int k = i + 1; k % 3 != 0; k ++){
				for(int h = j / 3 * 3;h < j / 3 * 3  + 3; h ++ ){
					if(board[i][j] == board[k][h]) 
						return false;
				}
			}
		}
	}
	return true;
}

 

10. 給定一個 × n 的二維矩陣表示一個圖像。將圖像順時針旋轉 90 度。

說明:你必須在原地旋轉圖像,這意味着你需要直接修改輸入的二維矩陣。請不要使用另一個矩陣來旋轉圖像。

給定 matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],

原地旋轉輸入矩陣,使其變爲:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

給定 matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 

原地旋轉輸入矩陣,使其變爲:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]

思路解析:左下右上連線,元素對換後再鏡像對稱,這種方法化繁爲簡。

public void rotate(int[][] matrix) {
	int len=matrix[0].length;
	int mid=len/2;
	for(int i=1;i<len;i++){
		for(int j=0;j<i;j++){
			int temp=matrix[i][j];
			matrix[i][j]=matrix[j][i];
			matrix[j][i]=temp;
		}
	}
	for(int i=0;i<len;i++){
		for(int j=0;j<mid;j++){
			int temp=matrix[i][j];
			matrix[i][j]=matrix[i][len-j-1];
			matrix[i][len-j-1]=temp;
		}
	}
}
//暴力
public void rotate(int[][] matrix) {
	int len = matrix.length;
	for (int i = 0; i < len / 2; i++) {
		int start = i;
		int end = len - i - 1;
		for (int j = 0; j < end - start; j++) {
			int temp = matrix[start][start + j];
			matrix[start][start + j] = matrix[end - j][start];
			matrix[end - j][start] = matrix[end][end - j];
			matrix[end][end - j] = matrix[start + j][end];
			matrix[start + j][end] = temp;
		}
	}      
}

 11.給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。

注意:答案中不可以包含重複的三元組。

例如, 給定數組 nums = [-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合爲:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

思路解析:排序,然後定義前後指針指向i+1與length,i爲遍歷的索引,內層循環當while(l<r)判斷if (nums[l] + nums[r] == sum) ,符合條件的存入,當左邊大時l++,否則r--,可以跳過重複元素。

public List<List<Integer>> threeSum(int[] nums) {
    Arrays.sort(nums);
    List<List<Integer>> ls = new ArrayList<>();
    for (int i = 0; i < nums.length - 2; i++) {
        if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) {  // 跳過可能重複的答案
            int l = i + 1, r = nums.length - 1, sum = 0 - nums[i];
            while (l < r) {
                if (nums[l] + nums[r] == sum) {
                    ls.add(Arrays.asList(nums[i], nums[l], nums[r]));
                    while (l < r && nums[l] == nums[l + 1]) l++;
                    while (l < r && nums[r] == nums[r - 1]) r--;
                    l++;
                    r--;
                } else if (nums[l] + nums[r] < sum) {
                    while (l < r && nums[l] == nums[l + 1]) l++;   // 跳過重複值
                    l++;
                } else {
                    while (l < r && nums[r] == nums[r - 1]) r--;
                    r--;
                }
            }
        }
    }
    return ls;
}

12.給定一個 m x n 的矩陣,如果一個元素爲 0,則將其所在行和列的所有元素都設爲 0。請使用原地算法。

輸入: 
[
  [1,1,1],
  [1,0,1],
  [1,1,1]
]
輸出: 
[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]
進階:
一個直接的解決方案是使用  O(mn) 的額外空間,但這並不是一個好的解決方案。
一個簡單的改進方案是使用 O(m + n) 的額外空間,但這仍然不是最好的解決方案。
你能想出一個常數空間的解決方案嗎?

思路解析:利用一個輔助數組來標記爲0的位置,再根據它來做替換。

public void setZeroes(int[][] matrix) {
    int h=matrix.length;
    int w=matrix[0].length;
    int[][] nub=new int[h][w];
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            if(matrix[i][j]==0){
                nub[i][j]=1;
            }
        } 
    }
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            if(nub[i][j]==1){
                change(i,j,w,h,matrix);
            }
        } 
    }
    
}

public void change(int i,int j,int w,int h,int[][] matrix) {
    for(int k=0;k<w;k++){
       matrix[i][k]=0;
   }
   for(int l=0;l<h;l++){
       matrix[l][j]=0;
   }
}

13.給定一個字符串數組,將字母異位詞組合在一起。字母異位詞指字母相同,但排列不同的字符串。

示例:

輸入: ["eat", "tea", "tan", "ate", "nat", "bat"],
輸出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
說明:

所有輸入均爲小寫字母。
不考慮答案輸出的順序。

 思路解析:每次循環取一個字符串,將它變爲字符數組排序,利用map來存入,當然存入前利用containKey()比較是否存在

public List<List<String>> groupAnagrams(String[] strs) {
    if (strs.length == 0) return new ArrayList();
    Map<String, List> ans = new HashMap<String, List>();
    for (String s : strs) {
        char[] ca = s.toCharArray();
        Arrays.sort(ca);
        String key = String.valueOf(ca);
        if (!ans.containsKey(key)) ans.put(key, new ArrayList());
        ans.get(key).add(s);
    }
    return new ArrayList(ans.values());
}

 

14.假設按照升序排序的數組在預先未知的某個點上進行了旋轉。( 例如,數組 [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

思路解析:將數組一分爲二,其中一定有一個是有序的,另一個可能是有序,也能是部分有序。此時有序部分用二分法查找。無序部分再一分爲二,其中一個一定有序,另一個可能有序,可能無序。就這樣循環.

public int search(int[] nums, int target) {
    return search(nums,target,0,nums.length-1);
}
private int search(int[] nums,int target,int i,int j)
{
    if(i>j) return -1;
    int mid=i+(j-i)/2;
    if(nums[mid]==target) return mid;
    
    if(nums[i]<nums[j]){
        if(nums[mid]<target) return search(nums,target,mid+1,j);
        else return search(nums,target,i,mid-1);
    }
    else{
        int ans=search(nums,target,i,mid-1);
        return ans!=-1?ans:search(nums,target,mid+1,j);
    }
}

15.給定一個大小爲 的數組,找到其中的衆數。衆數是指在數組中出現次數大於 ⌊ n/2 ⌋ 的元素。

你可以假設數組是非空的,並且給定的數組總是存在衆數。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章