🏡数组与排序
三数之和
给定一个包含 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;
}
}
}