Leetcode數據結構與算法(六)

[0081]按奇偶排序數組

給定一個非負整數數組 A,返回一個數組,在該數組中, A 的所有偶數元素之後跟着所有奇數元素。

你可以返回滿足此條件的任何數組作爲答案。 示例:

輸入:[3,1,2,4]
輸出:[2,4,3,1]
輸出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也會被接受。

提示:

1 <= A.length <= 5000
0 <= A[i] <= 5000

方法一:排序

class Solution {
    public int[] sortArrayByParity(int[] A) {
        Integer[] B = new Integer[A.length];
        for (int t = 0; t < A.length; ++t)
            B[t] = A[t];

        Arrays.sort(B, (a, b) -> Integer.compare(a%2, b%2));

        for (int t = 0; t < A.length; ++t)
            A[t] = B[t];
        return A;

        /* Alternative:
        return Arrays.stream(A)
                     .boxed()
                     .sorted((a, b) -> Integer.compare(a%2, b%2))
                     .mapToInt(i -> i)
                     .toArray();
        */
    }
}

方法二:兩次掃描

class Solution {
    public int[] sortArrayByParity(int[] A) {
        int[] ans = new int[A.length];
        int t = 0;

        for (int i = 0; i < A.length; ++i)
            if (A[i] % 2 == 0)
                ans[t++] = A[i];

        for (int i = 0; i < A.length; ++i)
            if (A[i] % 2 == 1)
                ans[t++] = A[i];

        return ans;
    }
}

方法三:原地算法

維護兩個指針 i 和 j,循環保證每刻小於 i 的變量都是偶數(也就是 A[k] % 2 == 0 當 k < i),所有大於 j 的都是奇數。

所以, 4 種情況針對 (A[i] % 2, A[j] % 2):

如果是 (0, 1),那麼 i++ 並且 j–。
如果是 (1, 0),那麼交換兩個元素,然後繼續。
如果是 (0, 0),那麼說明 i 位置是正確的,只能 i++。
如果是 (1, 1),那麼說明 j 位置是正確的,只能 j–。
通過這 4 種情況,循環不變量得以維護,並且 j-i 不斷變小。最終就可以得到奇偶有序的數組。

class Solution {
    public int[] sortArrayByParity(int[] A) {
        int i = 0, j = A.length - 1;
        while (i < j) {
            if (A[i] % 2 > A[j] % 2) {
                int tmp = A[i];
                A[i] = A[j];
                A[j] = tmp;
            }

            if (A[i] % 2 == 0) i++;
            if (A[j] % 2 == 1) j--;
        }

        return A;
    }
}

[0082]重新排列數組

給你一個數組 nums ,數組中有 2n 個元素,按 [x1,x2,…,xn,y1,y2,…,yn] 的格式排列。

請你將數組按 [x1,y1,x2,y2,…,xn,yn] 格式重新排列,返回重排後的數組。

示例 1:

輸入:nums = [2,5,1,3,4,7], n = 3
輸出:[2,3,5,4,1,7] 
解釋:由於 x1=2, x2=5, x3=1, y1=3, y2=4, y3=7 ,所以答案爲 [2,3,5,4,1,7]

示例 2:

輸入:nums = [1,2,3,4,4,3,2,1], n = 4
輸出:[1,4,2,3,3,2,4,1]

示例 3:

輸入:nums = [1,1,2,2], n = 2
輸出:[1,2,1,2]

提示:

1 <= n <= 500
nums.length == 2n
1 <= nums[i] <= 10^3

方法:

class Solution {
    public int[] shuffle(int[] nums, int n) {
        int[] ret = new int[2 * n];
        for(int i = 0; i < n; i++){
            ret[2 * i] = nums[i];
            ret[2 * i+1] = nums[i + n];
        }
        return ret;
    }
}

[0083]擁有最多糖果的孩子

給你一個數組 candies 和一個整數 extraCandies ,其中 candies[i] 代表第 i 個孩子擁有的糖果數目。

對每一個孩子,檢查是否存在一種方案,將額外的 extraCandies 個糖果分配給孩子們之後,此孩子有 最多 的糖果。注意,允許有多個孩子同時擁有 最多 的糖果數目。

示例 1:

輸入:candies = [2,3,5,1,3], extraCandies = 3
輸出:[true,true,true,false,true] 

解釋:

孩子 1 有 2 個糖果,如果他得到所有額外的糖果(3個),那麼他總共有 5 個糖果,他將成爲擁有最多糖果的孩子。
孩子 2 有 3 個糖果,如果他得到至少 2 個額外糖果,那麼他將成爲擁有最多糖果的孩子。
孩子 3 有 5 個糖果,他已經是擁有最多糖果的孩子。
孩子 4 有 1 個糖果,即使他得到所有額外的糖果,他也只有 4 個糖果,無法成爲擁有糖果最多的孩子。
孩子 5 有 3 個糖果,如果他得到至少 2 個額外糖果,那麼他將成爲擁有最多糖果的孩子。

示例 2:

輸入:candies = [4,2,1,1,2], extraCandies = 1
輸出:[true,false,false,false,false] 
解釋:只有 1 個額外糖果,所以不管額外糖果給誰,只有孩子 1 可以成爲擁有糖果最多的孩子。

示例 3:

輸入:candies = [12,1,12], extraCandies = 10
輸出:[true,false,true]

方法一:

class Solution {
    public List<Boolean> kidsWithCandies(int[] candies, int extraCandies) {
        List<Boolean> list = new ArrayList<Boolean>();
        int maxValue = 0;
        for(int i = 0; i < candies.length ; i++ )
            if(candies[i] > maxValue) maxValue = candies[i];
        for(int i = 0; i < candies.length ; i++ )
            list.add(candies[i] +extraCandies >= maxValue ? true : false);
        return list;
    }
}

[0084]在既定時間做作業的學生人數

給你兩個整數數組 startTime(開始時間)和 endTime(結束時間),並指定一個整數 queryTime 作爲查詢時間。

已知,第 i 名學生在 startTime[i] 時開始寫作業並於 endTime[i] 時完成作業。

請返回在查詢時間 queryTime 時正在做作業的學生人數。形式上,返回能夠使 queryTime 處於區間 [startTime[i], endTime[i]](含)的學生人數。

示例 1:

輸入:startTime = [1,2,3], endTime = [3,2,7], queryTime = 4
輸出:1
解釋:一共有 3 名學生。
第一名學生在時間 1 開始寫作業,並於時間 3 完成作業,在時間 4 沒有處於做作業的狀態。
第二名學生在時間 2 開始寫作業,並於時間 2 完成作業,在時間 4 沒有處於做作業的狀態。
第二名學生在時間 3 開始寫作業,預計於時間 7 完成作業,這是是唯一一名在時間 4 時正在做作業的學生。

示例 2:

輸入:startTime = [4], endTime = [4], queryTime = 4
輸出:1
解釋:在查詢時間只有一名學生在做作業。

示例 3:

輸入:startTime = [4], endTime = [4], queryTime = 5
輸出:0

示例 4:

輸入:startTime = [1,1,1,1], endTime = [1,3,2,4], queryTime = 7
輸出:0

示例 5:

輸入:startTime = [9,8,7,6,5,4,3,2,1], endTime = [10,10,10,10,10,10,10,10,10], queryTime = 5
輸出:5

提示:

startTime.length == endTime.length
1 <= startTime.length <= 100
1 <= startTime[i] <= endTime[i] <= 1000
1 <= queryTime <= 1000

方法一:

class Solution {
    public int busyStudent(int[] startTime, int[] endTime, int queryTime) {
        int ret = 0;
        for(int i = 0; i < startTime.length ; i++ )
            if(startTime[i] <= queryTime && endTime[i] >= queryTime)
                ret++;
        return ret;
    }
}

[0085]拿硬幣

桌上有 n 堆力扣幣,每堆的數量保存在數組 coins 中。我們每次可以選擇任意一堆,拿走其中的一枚或者兩枚,求拿完所有力扣幣的最少次數。

示例 1:

輸入:[4,2,1]

輸出:4

解釋:第一堆力扣幣最少需要拿 2 次,第二堆最少需要拿 1 次,第三堆最少需要拿 1 次,總共 4 次即可拿完。

示例 2:

輸入:[2,3,10]

輸出:8

限制:

1 <= n <= 4
1 <= coins[i] <= 10

方法一:

class Solution {
    public int minCount(int[] coins) {
        int ret = 0;
        for(int i = 0; i < coins.length ; i++ ){
            ret += coins[i] % 2 == 0 ? coins[i] /2 : coins[i] /2 + 1 ;
        }
        return ret;
    }
}

[0086]旅行終點站

給你一份旅遊線路圖,該線路圖中的旅行線路用數組 paths 表示,其中 paths[i] = [cityAi, cityBi] 表示該線路將會從 cityAi 直接前往 cityBi 。請你找出這次旅行的終點站,即沒有任何可以通往其他城市的線路的城市。

題目數據保證線路圖會形成一條不存在循環的線路,因此只會有一個旅行終點站。

示例 1:

輸入:paths = [["London","New York"],["New York","Lima"],["Lima","Sao Paulo"]]
輸出:"Sao Paulo" 
解釋:從 "London" 出發,最後抵達終點站 "Sao Paulo" 。本次旅行的路線是 "London" -> "New York" -> "Lima" -> "Sao Paulo" 。

示例 2:

輸入:paths = [["B","C"],["D","B"],["C","A"]]
輸出:"A"
解釋:所有可能的線路是:
"D" -> "B" -> "C" -> "A". 
"B" -> "C" -> "A". 
"C" -> "A". 
"A". 
顯然,旅行終點站是 "A" 。

示例 3:

輸入:paths = [["A","Z"]]
輸出:"Z"

方法一:

class Solution {
    public String destCity(List<List<String>> paths) {
		Map<String, Integer> map = new HashMap<String, Integer>();
		for (List<String> list : paths)
			map.put(list.get(0), 1);
		for (List<String> list : paths)
			if (map.get(list.get(1)) == null)
				return list.get(1);
		return null;
    }
}

[0087]通過翻轉子數組使兩個數組相等

給你兩個長度相同的整數數組 target 和 arr 。

每一步中,你可以選擇 arr 的任意 非空子數組 並將它翻轉。你可以執行此過程任意次。

如果你能讓 arr 變得與 target 相同,返回 True;否則,返回 False 。

示例 1:

輸入:target = [1,2,3,4], arr = [2,4,1,3]
輸出:true
解釋:你可以按照如下步驟使 arr 變成 target:
1- 翻轉子數組 [2,4,1] ,arr 變成 [1,4,2,3]
2- 翻轉子數組 [4,2] ,arr 變成 [1,2,4,3]
3- 翻轉子數組 [4,3] ,arr 變成 [1,2,3,4]
上述方法並不是唯一的,還存在多種將 arr 變成 target 的方法。

示例 2:

輸入:target = [7], arr = [7]
輸出:true
解釋:arr 不需要做任何翻轉已經與 target 相等。

示例 3:

輸入:target = [1,12], arr = [12,1]
輸出:true

示例 4:

輸入:target = [3,7,9], arr = [3,7,11]
輸出:false
解釋:arr 沒有數字 9 ,所以無論如何也無法變成 target 。

示例 5:

輸入:target = [1,1,1,1,1], arr = [1,1,1,1,1]
輸出:true

提示:

target.length == arr.length
1 <= target.length <= 1000
1 <= target[i] <= 1000
1 <= arr[i] <= 1000

方法一:(實際上是比較兩個數組是否相等,參考冒泡排序)

class Solution {
    public boolean canBeEqual(int[] target, int[] arr) {
       if (target.length != arr.length) {
            return false;
        }
        int[] tmp1 = new int[1001];
        int[] tmp2 = new int[1001];
        int len = target.length;
        for(int i = 0; i < len ; i++)
        {   tmp1[target[i]]++;
            tmp2[arr[i]]++;
        }
        for(int i = 0; i < 1001 ; i++)
        {
            if(tmp1[i] != tmp2[i]) return false;
        }
        return true;
    }
}

[0088]最大數值

編寫一個方法,找出兩個數字ab中最大的那一個。不得使用if-else或其他比較運算符。

示例:

輸入: a = 1, b = 2
輸出: 2

方法一:

class Solution {
    //公式:max(a,b) = (a + b + |a - b|) / 2
    int maximum(int a, int b) {
        long sum = (long)a + (long)b;
        long diff = (long)a - (long)b;
        long abs_diff = (diff ^ (diff >> 63)) - (diff >> 63);
        return  (int)((sum + abs_diff) / 2);
    }
}

絕對值的位運算,爲了迴避abs,利用位運算實現絕對值功能。

以int8_t爲例:分析運算:(var ^ (var >> 7)) - (var >> 7)

var >= 0: var >> 7 => 0x00,即:(var ^ 0x00) - 0x00,異或結果爲var

var < 0: var >> 7 => 0xFF,即:(var ^ 0xFF) - 0xFF,var ^ 0xFF是在對var的全部位取反,-0xFF <=> +1, 對signed int取反加一就是取其相反數。

舉個栗子🌰:var = -3 <=> 0xFD,(var ^ 0xFF) - 0xFF= 0x02 - 0xff= 0x03

基於上述分析:

類型 絕對值位運算
int8_t (var ^ (var >> 7)) - (var >> 7)
int16_t (var ^ (var >> 15)) - (var >> 15)
int32_t (var ^ (var >> 31)) - (var >> 31)
int64_t (var ^ (var >> 63)) - (var >> 63)

代碼中(diff^ (diff >> 63)) - (diff>> 63)就是在求取long (int64_t)的絕對值。

方法二:

class Solution {
    public int maximum(int a, int b) {
        // 先考慮沒有溢出時的情況,計算 b - a 的最高位,依照題目所給提示 k = 1 時 a > b,即 b - a 爲負
        int k = (b - a) >>> 31;
        // 再考慮 a b 異號的情況,此時無腦選是正號的數字
        int aSign = a >>> 31, bSign = b >>> 31;
        // diff = 0 時同號,diff = 1 時異號
        int diff = aSign ^ bSign;
        // 在異號,即 diff = 1 時,使之前算出的 k 無效,只考慮兩個數字的正負關係
        k = k & (diff ^ 1) | bSign & diff;
        return a * k + b * (k ^ 1);
    }

}

[0089]數組拆分 I

給定長度爲 2n 的數組, 你的任務是將這些數分成 n 對, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得從1 到 n 的 min(ai, bi) 總和最大。

示例 1:

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

輸出: 4
解釋: n 等於 2, 最大總和爲 4 = min(1, 2) + min(3, 4).

提示:

n 是正整數,範圍在 [1, 10000].
數組中的元素範圍在 [-10000, 10000].

方法一:排序

class Solution {
    public int arrayPairSum(int[] nums) {
        Arrays.sort(nums);
        int sum = 0;
        for (int i = 0; i < nums.length; i += 2) {
            sum += nums[i];
        }
        return sum;
    }
}

方法二:使用額外的空間

public class Solution {
    public int arrayPairSum(int[] nums) {
        int[] arr = new int[20001];
        int lim = 10000;
        for (int num: nums)
            arr[num + lim]++;
        int d = 0, sum = 0;
        for (int i = -10000; i <= 10000; i++) {
            //d:如果當前集合中有剩餘元素將被再次考慮,則此標誌設置爲 1。在從下一組中選擇元素時,會考慮已考慮的相同額外元素。
            sum += (arr[i + lim] + 1 - d) / 2 * i;
            d = (2 + arr[i + lim] - d) % 2;
        }
        return sum;
    }
} 

https://leetcode-cn.com/problems/array-partition-i/solution/shu-zu-chai-fen-i-by-leetcode/

[0090]獨一無二的出現次數

給你一個整數數組 arr,請你幫忙統計數組中每個數的出現次數。

如果每個數的出現次數都是獨一無二的,就返回 true;否則返回 false。

示例 1:

輸入:arr = [1,2,2,1,1,3]
輸出:true
解釋:在該數組中,1 出現了 3 次,2 出現了 2 次,3 只出現了 1 次。沒有兩個數的出現次數相同。

示例 2:

輸入:arr = [1,2]
輸出:false

示例 3:

輸入:arr = [-3,0,1,-3,1,1,1,-3,10,0]
輸出:true

提示:

  • 1 <= arr.length <= 1000
  • -1000 <= arr[i] <= 1000

方法一:

class Solution {
    public boolean uniqueOccurrences(int[] arr) {
        HashSet<Integer> set = new HashSet<>();  
        int[] ret = new int[2001];
        int base = 1000;

        for (int i = 0; i < arr.length; i ++)
            ret[arr[i] + base]++;
                
        for (int i = 0; i < ret.length; i ++)
        {
            if(ret[i]!=0){
                if(set.contains(ret[i])) return false;
                set.add(ret[i]);
            }
        }
        return true;
        
    }
}

[0091]遞增順序查找樹

給你一個樹,請你 按中序遍歷 重新排列樹,使樹中最左邊的結點現在是樹的根,並且每個結點沒有左子結點,只有一個右子結點。

示例 :

輸入:[5,3,6,2,4,null,8,1,null,null,null,7,9]
		5
      / \
    3    6
   / \    \
  2   4    8
 /        / \ 
1        7   9

輸出:[1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]

 1
  \
   2
    \
     3
      \
       4
        \
         5
          \
           6
            \
             7
              \
               8
                \
                 9  

提示:

給定樹中的結點數介於 1 和 100 之間。
每個結點都有一個從 0 到 1000 範圍內的唯一整數值。

方法一:中序遍歷 + 構造新的樹

我們在樹上進行中序遍歷,就可以從小到大得到樹上的節點。我們把這些節點的對應的值存放在數組中,它們已經有序。接着我們直接根據數組構件題目要求的樹即可。

class Solution {    
    public TreeNode increasingBST(TreeNode root) {
        List<Integer> vals = new ArrayList();
        inorder(root, vals);
        TreeNode ans = new TreeNode(0), cur = ans;
        for (int v: vals) {
            cur.right = new TreeNode(v);
            cur = cur.right;
        }
        return ans.right;
    }

    public void inorder(TreeNode node, List<Integer> vals) {
        if (node == null) return;
        inorder(node.left, vals);
        vals.add(node.val);
        inorder(node.right, vals);
    }
}

複雜度分析

時間複雜度:O(N)O(N),其中 NN 是樹上的節點個數。

空間複雜度:O(N)O(N)。

方法二:中序遍歷 + 更改樹的連接方式

和方法一類似,我們在樹上進行中序遍歷,但會將樹中的節點之間重新連接而不使用額外的空間。具體地,當我們遍歷到一個節點時,把它的左孩子設爲空,並將其本身作爲上一個遍歷到的節點的右孩子。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    TreeNode cur;
    public TreeNode increasingBST(TreeNode root) {
        TreeNode ans = new TreeNode(0);
        cur = ans;
        inorder(root);
        return ans.right;
    }

    public void inorder(TreeNode node) {
        if (node == null) return;
        inorder(node.left);
        node.left = null;
        cur.right = node;
        cur = node;
        inorder(node.right);
    }
}

複雜度分析

時間複雜度:O(N)O(N),其中 NN 是樹上的節點個數。

空間複雜度:O(H)O(H),其中 HH 是數的高度。

[0092]找出給定方程的正整數解

給出一個函數 f(x, y) 和一個目標結果 z,請你計算方程 f(x,y) == z 所有可能的正整數 數對 x 和 y。

給定函數是嚴格單調的,也就是說:

f(x, y) < f(x + 1, y)
f(x, y) < f(x, y + 1)

函數接口定義如下:

interface CustomFunction {
public:
  // Returns positive integer f(x, y) for any given positive integer x and y.
  int f(int x, int y);
};

如果你想自定義測試,你可以輸入整數 function_id 和一個目標結果 z 作爲輸入,其中 function_id 表示一個隱藏函數列表中的一個函數編號,題目只會告訴你列表中的 2 個函數。

你可以將滿足條件的 結果數對 按任意順序返回。

示例 1:

輸入:function_id = 1, z = 5
輸出:[[1,4],[2,3],[3,2],[4,1]]
解釋:function_id = 1 表示 f(x, y) = x + y

示例 2:

輸入:function_id = 2, z = 5
輸出:[[1,5],[5,1]]
解釋:function_id = 2 表示 f(x, y) = x * y

提示:

1 <= function_id <= 9
1 <= z <= 100
題目保證 f(x, y) == z 的解處於 1 <= x, y <= 1000 的範圍內。
在 1 <= x, y <= 1000 的前提下,題目保證 f(x, y) 是一個 32 位有符號整數。

方法一:暴力法

class Solution {
    public List<List<Integer>> findSolution(CustomFunction customfunction, int z) {
        List<List<Integer>> res = new ArrayList<>();
        for (int i = 1; i <= 1000; i++) {
            if (customfunction.f(i,1) > z) {
                break;
            }
            for (int j = 1; j <= 1000; j++) {
                if (customfunction.f(i,j) == z) {
                    List<Integer> list = new ArrayList<>();
                    list.add(i);
                    list.add(j);
                    res.add(list);
                    break;
                } else if(customfunction.f(i,j) > z){
                    break;
                }
            }
        }
        return res;  
    }
}

時間複雜度:O(n^2)

方法二:二分查找

class Solution {
    public List<List<Integer>> findSolution(CustomFunction customfunction, int z) {
        List<List<Integer>> res = new ArrayList<>();
        for (int i = 1; i <= 1000; i++) {
            if (customfunction.f(i,1) > z) {
                break;
            }
            int left = 1;
            int right = 1000;
            while (left <= right) {
                int mid = (right + left) / 2;
                int temp = customfunction.f(i,mid);
                if (temp == z) {
                    List<Integer> list = new ArrayList<>();
                    list.add(i);
                    list.add(mid);
                    res.add(list);
                    break;
                } else if (temp > z) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            }
        }
        return res;
    }
}

時間複雜度:O(nlogn)

方法三:雙指針法 (給定函數是嚴格單調的)

class Solution {
    public List<List<Integer>> findSolution(CustomFunction customfunction, int z) {
        List<List<Integer>> res = new ArrayList<>();
        int left = 1;
        int right = 1000;
        while (left <= 1000 && right >= 1) {
            int temp = customfunction.f(left,right);
            if (temp == z) {
                List<Integer> list = new ArrayList<>();
                list.add(left);
                list.add(right);
                res.add(list);
                left++;
            } else if (temp > z) {
                right--;
            } else {
                left++;
            }
        }
        return res;
    }
}

時間複雜度:O(n)

[0093]只出現一次的數字

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

說明:

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

示例 1:

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

示例 2:

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

方法一:

異或運算有以下三個性質。

  • 任何數和 0 做異或運算,結果仍然是原來的數。
  • 任何數和其自身做異或運算,結果是 0。
  • 異或運算滿足交換律和結合律。
class Solution {
    public int singleNumber(int[] nums) {
        int single = 0;
        for (int num : nums) {
            single ^= num;
        }
        return single;
    }
}
  • 時間複雜度:O(n),其中 n 是數組長度。只需要對數組遍歷一次。
  • 空間複雜度:O(1)。

[0094]特殊等價字符串組

你將得到一個字符串數組 A。

如果經過任意次數的移動,S == T,那麼兩個字符串 S 和 T 是特殊等價的。

一次移動包括選擇兩個索引 i 和 j,且 i % 2 == j % 2,交換 S[j] 和 S [i]。

現在規定,A 中的特殊等價字符串組是 A 的非空子集 S,這樣不在 S 中的任何字符串與 S 中的任何字符串都不是特殊等價的。

返回 A 中特殊等價字符串組的數量。

示例 1:
輸入:["a","b","c","a","c","c"]
輸出:3
解釋:3 組 ["a","a"],["b"],["c","c","c"]

示例 2:
輸入:["aa","bb","ab","ba"]
輸出:4
解釋:4 組 ["aa"],["bb"],["ab"],["ba"]

示例 3:
輸入:["abc","acb","bac","bca","cab","cba"]
輸出:3
解釋:3 組 ["abc","cba"],["acb","bca"],["bac","cab"]

示例 4:
輸入:["abcd","cdab","adcb","cbad"]
輸出:1
解釋:1 組 ["abcd","cdab","adcb","cbad"]


提示:
1 <= A.length <= 1000
1 <= A[i].length <= 20
所有 A[i] 都具有相同的長度。
所有 A[i] 都只由小寫字母組成。

https://leetcode-cn.com/problems/groups-of-special-equivalent-strings/solution/te-shu-deng-jie-zi-fu-chuan-zu-by-leetcode/

方法一:

class Solution {
    public int numSpecialEquivGroups(String[] A) {
        Set<String> seen = new HashSet();
        for (String S: A) {
            int[] count = new int[52];
            for (int i = 0; i < S.length(); ++i)
                count[S.charAt(i) - 'a' + 26 * (i % 2)]++;
            seen.add(Arrays.toString(count));
        }
        return seen.size();
    }
}

[0095]數字的補數

給定一個正整數,輸出它的補數。補數是對該數的二進制表示取反。

示例 1:

輸入: 5
輸出: 2
解釋: 5 的二進制表示爲 101(沒有前導零位),其補數爲 010。所以你需要輸出 2 。

示例 2:

輸入: 1
輸出: 0
解釋: 1 的二進制表示爲 1(沒有前導零位),其補數爲 0。所以你需要輸出 0 。

注意:

給定的整數保證在 32 位帶符號整數的範圍內。
你可以假定二進制數不包含前導零位。
本題與 1009 https://leetcode-cn.com/problems/complement-of-base-10-integer/ 相同

方法一:

class Solution {
    public int findComplement(int num) {
        int temp = num, c = 0;
        while(temp > 0){
            temp >>= 1;
            c =  (c << 1) + 1;
        }
        return num ^ c;       
    }
}

[0096]最小差值 I

給你一個整數數組 A,對於每個整數 A[i],我們可以選擇處於區間 [-K, K] 中的任意數 x ,將 x 與 A[i] 相加,結果存入 A[i] 。

在此過程之後,我們得到一些數組 B。

返回 B 的最大值和 B 的最小值之間可能存在的最小差值。

示例 1:
輸入:A = [1], K = 0
輸出:0
解釋:B = [1]

示例 2:
輸入:A = [0,10], K = 2
輸出:6
解釋:B = [2,8]

示例 3:
輸入:A = [1,3,6], K = 3
輸出:0
解釋:B = [3,3,3] 或 B = [4,4,4]

提示:

1 <= A.length <= 10000
0 <= A[i] <= 10000
0 <= K <= 10000

方法一:

class Solution {
    public int smallestRangeI(int[] A, int K) {
        int min = A[0], max = A[0];
        for (int x: A) {
            min = Math.min(min, x);
            max = Math.max(max, x);
        }
        return Math.max(0, max - min - 2*K);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章