題目總結
1.給你一個整數數組?hours
,表示以?小時?為單位的時間,返回一個整數,表示滿足?i < j
?且?hours[i] + hours[j]
?構成?整天?的下標對?i
,?j
?的數目。
整天?定義為時間持續時間是 24 小時的?整數倍?。
例如,1 天是 24 小時,2 天是 48 小時,3 天是 72 小時,以此類推。
示例 1:
輸入:?hours = [12,12,30,24,24]
輸出:?2
解釋:
構成整天的下標對分別是?(0, 1)
?和?(3, 4)
。
class Solution {
public:
? ? long long countCompleteDayPairs(vector<int> &hours) {
? ? ? ? long long ans = 0;
? ? ? ? int cnt[24]{};
? ? ? ? for (int t : hours) {
? ? ? ? ? ? // 先查詢 cnt,再更新 cnt,因為題目要求 i<j
? ? ? ? ? ? // 如果先更新,再查詢,就把 i=j 的情況也考慮進去了
? ? ? ? ? ? ans += cnt[(24 - t % 24) % 24];
? ? ? ? ? ? cnt[t % 24]++;
? ? ? ? }
? ? ? ? return ans;
? ? }
};
使用范圍基于的for循環 (for (int t : hours)) 遍歷 hours 數組中的每個元素 t。
在每次迭代中,首先計算 (24 - t % 24) % 24 來找到與當前小時數 t 相加能構成整天的那個小時數且位于當前小時數t之前(注意這里使用了兩次取模運算,第一次是為了確保 t 在0到23之間,第二次是為了處理 t 本身為24的倍數的情況)。
然后,將 cnt[(24 - t % 24) % 24] 的值加到 ans 上。這里 cnt[(24 - t % 24) % 24] 表示在遍歷到當前元素 t 之前,已經遍歷過的小時數中與 t 相加能構成整天的那些小時數出現的次數。
最后,更新 cnt[t % 24] 的值,表示當前小時數 t 出現的次數加1。這里再次使用取模運算來確保小時數在0到23之間。
2.
給你一個二進制數組?nums
?。
你可以對數組執行以下操作?任意?次(也可以 0 次):
- 選擇數組中?任意連續?3 個元素,并將它們?全部反轉?。
反轉?一個元素指的是將它的值從 0 變 1 ,或者從 1 變 0 。
請你返回將?nums
?中所有元素變為 1 的?最少?操作次數。如果無法全部變成 1 ,返回 -1 。
示例 1:
輸入:nums = [0,1,1,1,0,0]
輸出:3
解釋:
我們可以執行以下操作:
- 選擇下標為 0 ,1 和 2 的元素并反轉,得到?
nums = [1,0,0,1,0,0]
?。 - 選擇下標為 1 ,2 和 3 的元素并反轉,得到?
nums = [1,1,1,0,0,0]
?。 - 選擇下標為 3 ,4 和 5 的元素并反轉,得到?
nums = [1,1,1,1,1,1]
class Solution {
public:
? ? int minOperations(vector<int>& nums) {
? ? ? ? int n = nums.size();
? ? ? ? int ans = 0;
? ? ? ? for (int i = 0; i + 2 < n; i++) {
? ? ? ? ? ? if (nums[i] == 0) {
? ? ? ? ? ? ? ? for (int j = 0; j < 3; j++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? if(nums[i+j]==0)
? ? ? ? ? ? ? ? ? ? nums[i + j] = 1;
? ? ? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? nums[i+j]=0;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ans++;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (nums[n - 2] && nums[n - 1]) return ans;
? ? ? ? return -1;
? ? }
};
采用枚舉法,題目表示必須三個數進行改變,即如果最后nums[n-1]和nums[n-2]個數為1,則不能進行變換,所以單獨拿出來分析。
3.給你一個二維?二進制?數組?
grid
。請你找出一個邊在水平方向和豎直方向上、面積?最小?的矩形,并且滿足?grid
?中所有的 1 都在矩形的內部。返回這個矩形可能的?最小?面積。
示例 1:
輸入:?grid = [[0,1,0],[1,0,1]]
輸出:?6
解釋:
這個最小矩形的高度為 2,寬度為 3,因此面積為?
2 * 3 = 6
。
?class Solution {
public:
? ? int minimumArea(vector<vector<int>>& grid) {
? ? ? ? int h=0;
? ? ? ? int minh=1000;
? ? ? ? int l=0;
? ? ? ? int minl=1000;
? ? ? ? for(int i=0;i<grid.size();i++)
? ? ? ? {
? ? ? ? ? ? for(int j=0;j<grid[i].size();j++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if(grid[i][j])
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? minh=min(minh,i);
? ? ? ? ? ? ? ? ? ? h=max(h,i);
? ? ? ? ? ? ? ? ? ? l=max(l,j);
? ? ? ? ? ? ? ? ? ? minl=min(minl,j);
? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return (h-minh+1)*(l-minl+1);
? ? }
};
枚舉法,取包含1的最大行和最大列,包含1的最小行和最小列。 -
java總結
?繼承
對于兩個類中大量重復的代碼,我們可以將這些代碼放在另外一個類中,需要時再進行調用。java 的繼承通過 extends關鍵字來實現,實現繼承的類被稱為子類, 被繼承的類被稱為父類 。 父類和子類的關系 , 是一種一般和特殊的關系 。 例如水果和蘋果的關系 , 蘋果繼承了水果,蘋果是水果的子類,則蘋果是一種特殊的水果 。 因為子類是一種特殊的父類 , 因此父類包含的范圍總 比子類包含的范圍要大, 所以可以認為父類是大類, 而子類是小類 。
定義
Java 里子類繼承父類的語法格式如下
修飾符 class 子類 extends 父類 {}
:從上面語法格式來看, 定義子類的語法非常簡單 , 只需在原來的類定義上增加 extends 父類。
public class Fruit { public double weight; public void info(){ System.out.println( " 我是一個水果! 重"+ weight + "g!"); } }
接下來定義fruit的子類Apple
public class Apple extends Fruit { public static void main(String[] args) { Apple a = new Apple() ; a.weight = 56; a.info() ; } }
上面的 Apple 類基本只是一個空類,它只包含了一個 mainO方法,但程序中創建了 Apple 對象之后, 可以訪問該 Apple 對象的 weight 實例變量和 info()方法,這表明 Apple 對象也具有了 weight 實例變量和 info()方法,這就是繼承的作用 。
繼承的特點
Java 語言摒棄了 C++ 中難以理解的多繼承特征,即每個類最多只有一個直接父類,但支持多層繼承 。因為如果繼承的多個父類中有相同的方法,子類就無法確定繼承哪個方法。
如果定義一個 Java類時并未顯式指定這個類的直接父類,則這個類默認父類為Objec 類 。
重寫父類的方法
子類擴展了父類,子類是一個特殊的父類。 大部分時候,子類總是以父類為基礎 ,額外增加新的成員變量和方法。
但有一種情況例外 : 子類需要重寫父類的方法。
例如鳥類都包含了飛翔方法, 其中駝鳥是一種特殊的鳥類,因此駝烏應該是鳥的子類,因此它也將從烏類獲得飛翔方法,但這個飛翔方法明顯不適合駝鳥,為此,駝鳥需要重寫鳥類的方法。
下面程序先定義了 一個Bird類
public class Bird { // Bird 類的 fly() 方法 public void fly() { System.out.println(" 我在天空里自由自在地飛翔. .. "); } }
再定義了一個Buird的子類
public class Ostrich extends Bird { //重寫 Bird 類的 fly ()方法 public void fly() { System.out.println(" 我只能在地上奔跑 . . . ") ; } public static void main(String[] args) { Ostrich os = new Ostrich( ); //執行 Ostrich對象的 fly ()方法,將輸出"我只能在地上奔跑.. . os.fly (); } }
執行上面程序,將看到執行os.fly()時執行的不再是 Bird 類的方法,而是執行Ostrich 類的時方法。
這種子類包含與父類同名方法的現象被稱為方法重寫, 也被稱為方法覆蓋。可以說子類重寫了父類的方法, 也可以說子類覆蓋了父類的方法。
方法的重寫要遵循 " 兩同兩小一大"規則,
" 兩同"即方法名相同 、 形參列表相同 ;
" 兩小"指的是 子類方法返回值類型應比父類方法返回值類型更小或相等 , 子類方法聲明拋出的異常類應比父類方法聲明拋出的異常類更小或相等;
" 一大 "指的是子類方法的訪問權限應比父類方法的訪問權限更大或相等。
需要在子類方法中調用父類中被覆蓋的方法,則可以使用 super或者父類類名作為調用者來調用父類中被覆蓋的方法 。
如果父類方法具 private訪問權限,則該方法對其子類是隱藏的,因此其子類無法訪問該方法, 也就是無法重寫該方法 。
如果子類中定義了 一個與父類 private 方法具有相同的方法名 、 相同的形參列表相同的返回值類型的方法,依然不是重寫 , 只是在子類中重新定義了一個新方法.
調用父類的構造器
由于構造方法要與類名一致,所以子類不能繼承父類的構造方法。
但子類的構造器可以調用父類構造器的初始化代碼。
在一個構造器中調用另一個重載的構造器使用this調用來完成,
在子類構造器中調用父類構造器使用super調用來完成。
看下面程序定義了Base類和 Sub類,其中Sub類是 Base 類的子類,
class Base { public double size; public String name; public Base(double size , String name) { this . size = size ; this . name = name; } } public class Sub extends Base { public String color; public Sub(double size , String name , String color) { super(size , name) ; this.color = color; } public static void main(String[] args) { Sub s = new Sub(5.6 , "測試對象","紅色" ) ; System.out.println(s.size + "--" + s.name+"--"+s.color); } }
子類的構造方法會先訪問父類的無參構造,以防需要父類中數據進行初始化
成員變量
對與父類中的成員變量,子類中是可以進行調用,并賦值。但如果父類中的成員變量被private修飾則不能進行操作。