🏡數組與排序
三數之和
給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。 注意:答案中不可以包含重複的三元組。
class Solution {
public static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList();
int len = nums.length;
if(nums == null || len < 3) return ans;
Arrays.sort(nums); // 排序
for (int i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果當前數字大於0,則三數之和一定大於0,所以結束循環
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.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 (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
}
}
島嶼的最大面積
給定一個包含了一些 0 和 1的非空二維數組 grid , 一個 島嶼 是由四個方向 (水平或垂直) 的 1 (代表土地) 構成的組合。你可以假設二維矩陣的四個邊緣都被水包圍着。
找到給定的二維數組中最大的島嶼面積。(如果沒有島嶼,則返回面積爲0。)
class Solution {
public int maxAreaOfIsland(int[][] grid) {
// 記錄最大值
int max = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
int temp = DFS(i, j, grid);
max = temp > max ? temp : max;
}
}
return max;
}
public int DFS(int i, int j, int[][] grid) {
// 邊界判斷
if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length) {
return 0;
}
// 島嶼爲0、1判斷
if (grid[i][j] == 0) {
return 0;
}
// 標記grid[i][j] = 0
grid[i][j] = 0;
// 四個方向遞歸
return 1 + DFS(i-1, j, grid)
+ DFS(i+1, j, grid)
+ DFS(i, j-1, grid)
+ DFS(i, j+1, grid);
}
}
搜索旋轉排序數組
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重複的元素。
你的算法時間複雜度必須是 O(log n) 級別。
代碼:
class Solution {
public int search(int[] nums, int target) {
return search(nums, 0, nums.length-1, target);
}
private int search(int[] nums, int l, int r,int target){
if(l > r){
return -1;
}
int mid = (l+r)/2;
if(nums[mid] == target){
return mid;
}
if(nums[mid] < nums[r]){//右側有序
if(target > nums[mid] && target <= nums[r]){//目標值在右側
return search(nums, mid+1, r, target);
}else{
return search(nums, l, mid-1, target);
}
}else{
if(target < nums[mid] && target >= nums[l]){
return search(nums, l, mid-1, target);
}else{
return search(nums, mid+1, r, target);
}
}
}
}
朋友圈
班上有 N 名學生。其中有些人是朋友,有些則不是。他們的友誼具有是傳遞性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那麼我們可以認爲 A 也是 C 的朋友。所謂的朋友圈,是指所有朋友的集合。
給定一個 N * N 的矩陣 M,表示班級中學生之間的朋友關係。如果M[i][j] = 1,表示已知第 i 個和 j 個學生互爲朋友關係,否則爲不知道。你必須輸出所有學生中的已知的朋友圈總數。
代碼:
class Solution {
public int findCircleNum(int[][] M) {
int len=M.length;
if(len<2){
return len;
}
int []help=new int[len];
int cnt=0;
for(int i=0;i<len;++i){
if(help[i]==0){
bfs(M,i,help);
cnt++;
}
}
return cnt;
}
private void bfs(int[][] graph,int node,int[] help){
int[] queue=new int[graph.length];
int cnt=1;
queue[0]=node;
help[node]=1;
for (int i=0;i<cnt;++i){
for (int j=0;j<graph[queue[i]].length;++j){
if (queue[i]!=j&&graph[queue[i]][j]==1&&help[j]==0){
help[j]=1;
queue[cnt++]=j;
}
}
}
}
}
接雨水
給定 n 個非負整數表示每個寬度爲 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。
class Solution {
public int trap(int[] height) {
if(height == null || height.length <= 2)
return 0;
int maxL = height[0];
int[] maxRs = new int[height.length];
int waterSum = 0;//計算總的水量
int maxR = 0;
for(int i = height.length - 1; i >= 0; i--){
if(height[i] > maxR) {
maxRs[i] = maxR = height[i];
}
else {
maxRs[i] = maxR;
}
}
for(int i = 1; i < height.length - 1; i++){
if(height[i] > maxL) {
maxL = height[i];//更新左邊最大值
}
waterSum += Math.max(Math.min(maxL, maxRs[i]) - height[i], 0);
}
return waterSum;
}
}
反轉鏈表
反轉一個單鏈表。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
兩數相加
給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1==null){//因爲l1是基準鏈表,要是l1到尾部了,l2就算還有,直接返回l2的剩餘部分
return l2;
}
if(l2==null){//這裏l2到尾部了,l1需要進行判斷,尾部是否大於10,要去進位。
//比如l1:9,9 .l2:9 一次運算過後l2到尾部,l1變爲8,10,這時候依然當做l2有個0去進位
if(l1.val>=10){
l2 = new ListNode(0);
l2.next = null;
}else{
return l1;
}
}
int temp = l1.val+l2.val;
l1.val = temp%10;
if(temp>=10){ //說明l1應該進位
if(l1.next==null){//要是l1沒有下一位,則new一個節點進行連接
l1.next = new ListNode(1);
}else{
l1.next.val++; //l1有下一個節點,直接下一個節點的值加一
}
}
l1.next = addTwoNumbers(l1.next,l2.next);//用於重新連接攜帶新的值的每個l1節點
return l1;
}
}
買賣股票的最佳時機
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
如果你最多隻允許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。
注意你不能在買入股票前賣出股票。
class Solution {
public static void main(String args[]) {
int[] prices = new int[] {7,1,5,3,6,4};
int max = maxProfit(prices);
System.out.println(max);
}
public static int maxProfit(int[] prices) {
if(prices.length <= 1) {
return 0;
}
int min = prices[0];
int max = 0;
for(int i = 1; i < prices.length; i++) {
max = Math.max(max, prices[i] - min);
min = Math.min(min, prices[i]);
}
return max;
}
}
最大子序和
給定一個整數數組 nums ,找到一個具有最大和的連續子數組(子數組最少包含一個元素),返回其最大和。
public class Solution {
public int maxSubArray(int[] nums) {
int len = nums.length;
if (len == 0) {
return 0;
}
int[] dp = new int[len];
dp[0] = nums[0];
for (int i = 1; i < len; i++) {
dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
}
// 最後這一步,是求一個全局的最優值
int res = dp[0];
for (int i = 1; i < len; i++) {
res = Math.max(res,dp[i]); } return res;
}
}
最小棧
設計一個支持 push,pop,top 操作,並能在常數時間內檢索到最小元素的棧。
push(x) – 將元素 x 推入棧中。
pop() – 刪除棧頂的元素。
top() – 獲取棧頂元素。
getMin() – 檢索棧中的最小元素。
class MinStack {
private Node head;
public void push(int x) {
if (head == null)
head = new Node(x, x);
else
head = new Node(x, Math.min(x, head.min), head);
}
public void pop() {
head = head.next;
}
public int top() {
return head.val;
}
public int getMin() {
return head.min;
}
private class Node {
int val;
int min;
Node next;
private Node(int val, int min) {
this(val, min, null);
}
private Node(int val, int min, Node next) {
this.val = val;
this.min = min;
this.next = next;
}
}
}