最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
Java版本:
public static int maxSubArray(int[] nums) {
int pre = 0, res = nums[0];
for (int val : nums){
pre = Math.max(val, val + pre);
res = Math.max(res, pre);
}
return res;
}
Python版本:
# 最大子序和
# 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
class Solution:
def maxSubArray(self, nums: list) -> int:
pre, res = 0, nums[0]
for i in range(0,len(nums)):
pre = max(nums[i], pre + nums[i])
res = max(res, pre)
return res
# 测试
s = Solution()
nums = [-2,1,-3,4,-1,2,1,-5,4]
print(s.maxSubArray(nums))
答案:
6
跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
Java版本:
/*
依次遍历数组中的每一个位置,并实时维护 最远可以到达的位置
*/
public static boolean canJump(int[] nums) {
int max = 0;
for (int i = 0 ; i < nums.length ; i++){
max = Math.max(max, i + nums[i]);
if (max >= nums.length - 1){
return true;
}
}
return false;
}
Python版本:
# 跳跃游戏
class Solution:
def canJump(self, nums: list) -> bool:
n = len(nums)
maxVal = 0
for i in range(0, n):
if i <= maxVal:
maxVal = max(maxVal, i+nums[i])
if maxVal >= n-1:
return True
return False
# 测试
s = Solution()
nums = [2,3,1,1,4];
print(s.canJump(nums))
# 答案:
True
螺旋矩阵
给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
Java版本:
/*旋转添加输出*/
public static List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
if (matrix == null || matrix.length == 0 || matrix[0].length == 0){
return res;
}
int up = 0, down = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
int count = matrix.length * matrix[0].length;
while (count > 0){
for (int i = left ; count > 0 && i <= right; i++){
res.add(matrix[up][i]);
count--;
}
up++;
for (int i = up ; count > 0 && i <= down; i++){
res.add(matrix[i][right]);
count--;
}
right--;
for (int i = right; count > 0 && i >= left ; i--){
res.add(matrix[down][i]);
count--;
}
down--;
for (int i = down; count > 0 && i >= up ; i--){
res.add(matrix[i][left]);
count--;
}
left++;
}
return res;
}
Python版本:
# 螺旋矩阵
class Solution:
def spiralOrder(self, matrix: list) -> list:
if not matrix or not matrix[0]:
return list()
left, up = 0, 0
down, right = len(matrix)-1, len(matrix[0])-1
count = len(matrix) * len(matrix[0])
res = list()
while count > 0:
for i in range(left, right+1):
if count > 0:
res.append(matrix[up][i])
count -= 1
up += 1
for i in range(up, down+1):
if count > 0:
res.append(matrix[i][right])
count -= 1
right -= 1
for i in range(right, left-1, -1):
if count > 0:
res.append(matrix[down][i])
count -= 1
down -= 1
for i in range(down, up-1, -1):
if count > 0:
res.append(matrix[i][left])
count -= 1
left += 1
return res
# 测试
s = Solution()
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
print(s.spiralOrder(matrix))
# 答案:
[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
合并区间
给出一个区间的集合,请合并所有重叠的区间。
Java解法:
public static int[][] merge(int[][] intervals) {
/*先将每个区间的左端点,从小到大排序*/
Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
int n = intervals.length;
int [][]res = new int[n][2];
int idx = -1;
for (int[] interval: intervals) {
/*
如果结果数组是空的,或者当前区间的起始位置 > 结果数组中最后区间的终止位置,
则不合并,直接将当前区间加入结果数组。
*/
if (idx == -1 || interval[0] > res[idx][1]) {
res[++idx] = interval;
} else {
// 反之将当前区间合并至结果数组的最后区间
res[idx][1] = Math.max(res[idx][1], interval[1]);
}
}
return Arrays.copyOf(res, idx + 1);
}
Python解法:
# 合并区间
class Solution:
def merge(self, intervals: list) -> list:
if not intervals: return []
intervals.sort()
res = [intervals[0]]
for x, y in intervals[1:]:
if res[-1][1] < x:
res.append([x, y])
else:
res[-1][1] = max(y, res[-1][1])
return res
# 测试
s = Solution()
intervals = [[1,3],[2,6],[8,10],[15,18]]
print(s.merge(intervals))
# 答案:
[[1, 6], [8, 10], [15, 18]]
插入区间
给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
Python版本:
# 插入区间
class Solution:
def insert(self, intervals: list, newInterval: list) -> list:
left, right = newInterval
flag = False
res = list()
for le, ri in intervals:
if le > right:
# 在插入区间的右侧且无交集
if not flag:
res.append([left, right])
flag = True
res.append([le, ri])
elif ri < left:
# 在插入区间的左侧且无交集
res.append([le, ri])
else:
# 与插入区间有交集,计算它们的并集
left = min(left, le)
right = max(right, ri)
if not flag:
res.append([left, right])
return res
# 测试
s = Solution()
intervals = [[1,3],[4,5],[7,9]]
newInterval = [2,5]
print(s.insert(intervals,newInterval))
# 答案:
[[1, 5], [7, 9]]
Java版本:
public static int[][] insert(int[][] intervals, int[] newInterval) {
if (newInterval == null){
return intervals;
}
ArrayList<int[]> res = new ArrayList<>();
ArrayList<int[]> cur = new ArrayList<>();
for (int []row : intervals){
cur.add(row);
}
int i = 0;
while (i < cur.size() && newInterval[0] > cur.get(i)[0]){
i++;
}
/*按顺序插入*/
cur.add(i, newInterval);
res.add(cur.get(0));
i = 0;
while (++i < cur.size()){
/*比较左端点,加入数据*/
if(cur.get(i)[0] > res.get(res.size() - 1)[1]) {
res.add(cur.get(i));
continue;
}
/*比较右端点谁大,设置区间值*/
int right = Math.max(res.get(res.size() - 1)[1], cur.get(i)[1]);
res.set(res.size() - 1, new int[]{
res.get(res.size() - 1)[0], right});
}
int[][] ans = new int[res.size()][];
for(int j = 0; j < res.size(); j++) {
ans[j] = res.get(j);
}
return ans;
}
最后一个单词的长度
给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s,返回其最后一个单词的长度。如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。
如果不存在最后一个单词,请返回 0 。
说明:一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。
Java版本:
/*
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:36.4 MB, 在所有 Java 提交中击败了97.01%的用户
*/
public static int lengthOfLastWord(String s) {
//去除前后空格
s = s.trim();
int count = 0;
for (int i = s.length()-1; i >= 0 && s.charAt(i) != ' '; i--){
count++;
}
return count;
}
Python版本:
# 最后一个单词的长度
class Solution:
def lengthOfLastWord(self, s: str) -> int:
# 去除前后空格
s = s.strip()
count = 0
for i in range(len(s)-1, -1, -1):
if s[i] != ' ':
count += 1
else:
break
return count
# 测试
s = Solution()
arr = "hello world"
print(s.lengthOfLastWord(arr))
# 答案:
5
螺旋矩阵2
给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
Java解法:
/*
顺时针赋值
*/
public static int[][] generateMatrix(int n) {
int left = 0 , up = 0;
int right = n-1 , dowm = n-1;
int [][]res = new int[n][n];
int flag = n * n , val = 1;
while (val <= flag){
for (int i = left; i <= right ; i++){
res[up][i] = val++;
}
up++;
for (int i = up; i <= dowm ; i++){
res[i][right] = val++;
}
right--;
for (int i = right; i >= left ; i--){
res[dowm][i] = val++;
}
dowm--;
for (int i = dowm ; i >= up ; i--){
res[i][left] = val++;
}
left++;
}
return res;
}
Python解法:
class Solution:
def generateMatrix(self, n: int) -> list:
left, up = 0, 0
down, right = n - 1, n - 1
val = 1
res = [[0 for i in range(n)] for i in range(n)]
while val <= n*n:
for i in range(left, right + 1):
if val <= n*n:
res[up][i] = val
val += 1
up += 1
for i in range(up, down + 1):
if val <= n*n:
res[i][right] = val
val += 1
right -= 1
for i in range(right, left - 1, -1):
if val <= n*n:
res[down][i] = val
val += 1
down -= 1
for i in range(down, up - 1, -1):
if val <= n*n:
res[i][left] = val
val += 1
left += 1
return res
排列序列
给定 n 和 k,返回第 k 个排列
Java版本:
/**
* 思路:数学 + 缩小问题规模
* 对于 n 个不同的元素(例如数 1, 2,⋯,n),它们可以组成的排列总数目为 n!。
* 首先确定排列中的首个元素 a1,根据上述的结论,我们可以知道:
* 以1为a1作为首个的排列一共有 (n-1)! 个;
* 以2为a1作为首个的排列一共有 (n-1)! 个
* ...
* 以n为a1的为首个的排列一共有 (n-1)! 个。
* 也就是说:
* 最高位为 1 对应的是第 1 种~共 (n-1)! 种排列,依次类推,最高位为 2 对应的是共 (n-1)!+1 种~共 2(n-1)! 种排列,最高位为 3 对应的是共 2(n-1)!+1 种~共 3(n-1)! 种排列。
* 想必大家已经发现规律了,我们就借助这个规律来解题。
*
* 回到题目上来,我们怎么求出第 k 个排列?借助上面的思路,我们用一个递归的过程来求解,以 n=4 ,k=7 为例:
* 固定最高位为 1 不变,有 (n-1)!=6 种排列,固定最高位为 2 不变,也有 (n-1)!=6 种排列,所以 k=7 一定是以 2 开头的。所以我们找到了最高位2。
* 还剩3个数:1,3,4。更新 k -= 1*(n-1)!=3 , n -= 1 。问题就变成了 nums=[1,3,4], k=3 。以同样的方法找当前最高位,为 1 。
* 还剩2个数:3,4。更新 k -= 1*(n-1)! =1 , n -= 1 ,问题就变成了 nums=[3,4], k=1 。
*/
public static String getPermutation(int n, int k) {
List<Integer> list = new ArrayList<>();
for( int i = 1; i <= n; i++ ) {
list.add(i);
}
StringBuilder res = new StringBuilder();
while(n > 0) {
/*算出多少种排列*/
int curCom = cal(--n);
/*相除取整,求出首位*/
int group = (k-1)/curCom;
res.append(list.get(group));
/*删除已用过的数字*/
list.remove(group);
/*减去用了的排列种数*/
k -= (group*curCom);
}
return res.toString();
}
/*阶乘*/
private static int cal(int num) {
int res = 1;
for(int i = 1; i <= num; i++) {
res *= i;
}
return res;
}
Python版本:
class Solution:
def getPermutation(self, n: int, k: int) -> str:
nums = [i for i in range(1, n+1)]
res = str()
while n > 0:
# 算出排列种数
n -= 1
numcal = self.cal(n)
# 相除取整,求出下一位,(被除数不为0,这里做判断)
if k-1 != 0:
grop = (k - 1) // numcal
else:
grop = 0
# 添加到结果
res += str(nums[grop])
# 删除用过的数字
nums.remove(nums[grop])
# 减去用了的排列种数
k = k - grop * numcal
return res
# 阶乘
def cal(self, val: int) -> int:
res = 1
for i in range(1, val+1):
res *= i
return res
不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
Java解法:
/*
动态规划:
用 f(i, j)f(i,j) 表示从左上角走到 (i, j)(i,j) 的路径数量,其中 ii 和 jj 的范围分别是 [0, m) 和 [0, n)
由于我们每一步只能从向下或者向右移动一步,因此要想走到 (i, j),如果向下走一步,那么会从 (i-1, j) 走过来;如果向右走一步,那么会从 (i, j-1) 走过来。
因此我们可以写出动态规划转移方程:f(i,j)=f(i−1,j)+f(i,j−1)
初始条件为 f(0,0)=1f(0,0)=1,即从左上角走到左上角有一种方法。最终的答案即为 f(m-1,n-1)f(m−1,n−1)。
需要注意的是,如果 i=0,那么 f(i-1,j) 并不是一个满足要求的状态,我们需要忽略这一项;同理,如果 j=0,那么 f(i,j−1) 并不是一个满足要求的状态,我们需要忽略这一项
*/
public static int uniquePaths(int m, int n) {
int [][]dp = new int[m][n];
for (int i = 0 ; i < m ; i++){
dp[i][0] = 1;
}
for (int j = 0 ; j < n ; j++){
dp[0][j] = 1;
}
for (int i = 1 ; i < m ; i++){
for (int j = 1 ; j < n ; j++){
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
Python解法:
# 不同路径
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 构建dp二维数组
dp = [[0 for j in range(n)] for i in range(m)]
for i in range(m):
dp[i][0] = 1
for j in range(n):
dp[0][j] = 1
for i in range(1,m):
for j in range(1,n):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
# 测试
s = Solution()
m, n = 3, 7
print(s.uniquePaths(m, n))
# 答案:
28
不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
Java解法:
/*
动态规划
*/
public static int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int [][]dp = new int[m][n];
/*初始化列*/
for (int i = 0; i < m ; i++){
if (obstacleGrid[i][0] == 1){
break;
}
dp[i][0] = 1;
}
/*初始化行*/
for (int j = 0; j < n ; j++){
if (obstacleGrid[0][j] == 1){
break;
}
dp[0][j] = 1;
}
for (int i = 1 ; i < m ; i++){
for (int j = 1 ; j < n ; j++){
/*防止当前点是障碍物*/
dp[i][j] = obstacleGrid[i][j] == 1 ? 0 : dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
Python解法:
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: list) -> int:
m, n = len(obstacleGrid), len(obstacleGrid[0])
# 构建dp二维数组
dp = [[0 for j in range(n)] for i in range(m)]
# 初始化列
for i in range(m):
if obstacleGrid[i][0] == 1:
break
dp[i][0] = 1
# 初始化行
for j in range(n):
if obstacleGrid[0][j] == 1:
break
dp[0][j] = 1
for i in range(1, m):
for j in range(1, n):
# 防止当前点是障碍物
if obstacleGrid[i][j] == 1:
dp[i][j] = 0
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
# 测试
s = Solution()
obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
print(s.uniquePathsWithObstacles(obstacleGrid))
# 答案:
2
最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
Java解法:
public static int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0){
return 0;
}
int m = grid.length , n = grid[0].length;
int [][]dp = new int[m][n];
/*初始化原点,行和列*/
dp[0][0] = grid[0][0];
for (int i = 1 ; i < m ; i++){
dp[i][0] = dp[i-1][0] + grid[i][0];
}
for (int j = 1 ; j < n ; j++){
dp[0][j] = dp[0][j-1] + grid[0][j];
}
/*动态规划*/
for (int i = 1 ; i < m ; i++){
for (int j = 1 ; j < n ; j++){
dp[i][j] = Math.min(dp[i-1][j] , dp[i][j-1]) + grid[i][j];
}
}
return dp[m-1][n-1];
}
Python解法:
# 最小路径和
class Solution:
def minPathSum(self, grid: list) -> int:
if not grid or len(grid) == 0 or len(grid[0]) == 0:
return 0
m, n = len(grid), len(grid[0])
dp = [[0 for _ in range(n)] for _ in range(m)]
# 初始化
dp[0][0] = grid[0][0]
for i in range(1, m):
dp[i][0] = dp[i-1][0] + grid[i][0]
for j in range(1, n):
dp[0][j] = dp[0][j-1] + grid[0][j]
for i in range(1, m):
for j in range(1, n):
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
return dp[m-1][n-1]
# 测试
s = Solution()
grid = [[1,3,1],[1,5,1],[4,2,1]]
print(s.minPathSum(grid))
# 答案:
7
旋转链表
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
/*
先将链表闭合成环
找到相应的位置断开这个环,确定新的链表头和链表尾
*/
public static ListNode rotateRight(ListNode head, int k) {
if (head == null){
return null;
}
ListNode tail = head;
int n = 1; //最终会是链表长度
while (tail.next != null){
tail = tail.next;
n++;
}
/*把尾节点 指向 头结点,这样就形成闭环链表*/
tail.next = head;
/*
找到对应新头节点
链表头在位置 n-k 处,其中 n 是链表中点的个数,新的链表尾就在头的前面,位于位置 n-k-1。
*/
ListNode new_tail = head;
for (int i = 0 ; i < (n - k) % n - 1 ; i++){
new_tail = new_tail.next;
}
ListNode new_head = new_tail.next;
// 断开闭环
new_tail.next = null;
return new_head;
}
有效数字
证给定的字符串是否可以解释为十进制数字。
Java解法:
/*
遍历目标字符串
1.判断是否属于数字的0~9区间
2.遇到点的时候,判断前面是否有点或者E,都需要return false
3.遇到E的时候,判断前面数字是否合理,是否有E,并把num置为false,防止E后无数字
4.遇到-+的时候,判断是否是第一个,如果不是第一个判断是否在E后面,都不满足则return false
5.其他情况都为false
最后返回num的结果即可
*/
public static boolean isNumber(String s) {
if (s == null || s.length() == 0){
return false;
}
/*num:数字,dot:点,e:指数e*/
boolean num=false;
boolean dot=false;
boolean e=false;
char []c = s.trim().toCharArray();
for (int i = 0 ; i < c.length ; i++){
if (c[i] >= '0' && c[i] <= '9'){
num = true;
}else if (c[i] == '.'){
if (dot || e){
return false;
}
dot = true;
}else if (c[i] == 'e' || c[i] == 'E'){
if (!num || e){
return false;
}
num = false;
e = true;
}else if (c[i] == '+' || c[i] == '-'){
if(i != 0 && c[i-1] != 'e' && c[i-1]!='E'){
return false;
}
}else{
return false;
}
}
return num;
}
Python解法:
class Solution:
def isNumber(self, s: str) -> bool:
if not s or len(s) == 0:
return False
num, dot, e = False, False, False
# 去除空格
s = s.strip()
for i in range(len(s)):
if '0' <= s[i] <= '9':
num = True
elif s[i] == '.':
if dot or e:
return False
dot = True
elif s[i] == 'e' or s[i] == 'E':
if not num or e:
return False
num = False
e = True
elif s[i] == '+' or s[i] == '-':
if i != 0 and s[i-1] != 'e' and s[i-1] != 'E':
return False
else:
return False
return num
# 测试
s = Solution()
d = "1 "
print(s.isNumber(d))
# 答案:
True
二进制求和
给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。
Java解法:
public static String addBinary(String a, String b) {
if(a == null) return b;
else if(b == null) return a;
int flag = 0;
int n = Math.max(a.length(), b.length());
StringBuilder res = new StringBuilder();
for (int i = 0 ; i < n ; i++){
flag += i < a.length() ? (a.charAt(a.length() - i -1) -'0') : 0;
flag += i < b.length() ? (b.charAt(b.length() - i -1) -'0') : 0;
res.append((char)(flag % 2 + '0'));
flag /= 2;
}
if (flag > 0){
res.append(1);
}
return res.reverse().toString();
}
Python解法:
class Solution:
def addBinary(self, a: str, b: str) -> str:
if not a:
return b
elif not b:
return a
n = max(len(a), len(b))
flag = 0
tmp = list()
for i in range(n):
if i < len(a):
flag += int(a[len(a) - i - 1])
else:
flag += 0
if i < len(b):
flag += int(b[len(b) - i - 1])
else:
flag += 0
tmp.append(str(flag % 2))
flag //= 2
if flag > 0:
tmp.append("1")
return ''.join(tmp[::-1])
# 测试
s = Solution()
a, b = "11", "1"
print(s.addBinary(a, b))
# 答案:
100
加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
Java解法:
public static int[] plusOne(int[] digits) {
for (int i = digits.length - 1 ; i >= 0 ; i--){
digits[i]++;
digits[i] = digits[i] % 10;
if (digits[i] != 0){
return digits;
}
}
digits = new int[digits.length + 1];
digits[0] = 1;
return digits;
}
Python解法:
# 加一
class Solution:
def plusOne(self, digits: list) -> list:
for i in range(len(digits)-1, -1, -1):
digits[i] += 1
digits[i] %= 10
if digits[i] != 0:
return digits
digits.insert(0, 1)
return digits
# 测试
s = Solution()
digits = [1,0,9]
print(s.plusOne(digits))
# 测试
[1, 1, 0]
文本左右对齐
给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。
你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ’ ’ 填充,使得每行恰好有 maxWidth 个字符。
要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。
文本的最后一行应为左对齐,且单词之间不插入额外的空格。
Java版本:
/*
普通情况
一行放wdCnt个单词, 剩余blank个空格,
每两个单词之间的空格数为 blank / (count - 1) + mod > 0 ? 1: 0
mod = blank / (count - 1)
if(mod > 0) mod--;
特殊情况1, 如果是最后一行, 单词之间只占一个空格
特殊情况2, 如果一行只有一个单词, 补齐右边的空格
*/
public static List<String> fullJustify(String[] words, int maxWidth) {
List<String> list = new ArrayList<>();
int n = words.length;
int i = 0, j = 0, blank, count, curlen;
while (i < n){
curlen = maxWidth;
count = 0;
blank = 0;
/*求出一行能放的单词数*/
while (j < n && curlen >= words[j].length()){
curlen -= words[j].length();
count++;
blank++;
curlen -= 1; /*减去空格*/
j++;
}
blank += curlen; /*空格数*/
StringBuilder sb = new StringBuilder();
/*如果是最后一行,单词之间只占一个空格*/
if (j >= n){
while (i < j){
sb.append(words[i++]).append(" ");
}
sb.deleteCharAt(sb.length()-1);
while (sb.length() < maxWidth){
sb.append(" ");
}
}else if (count == 1) {
/*如果一行只有一个单词, 补齐右边的空格*/
while (i < j){
sb.append(words[i++]).append(" ");
}
sb.deleteCharAt(sb.length()-1);
while (sb.length() < maxWidth){
sb.append(" ");
}
}else{
/*普通情况*/
int mod = blank % (count - 1);
int ans = blank / (count - 1);
while(i < j){
sb.append(words[i++]);
int k = ans + (mod > 0 ? 1: 0);
mod--;
if(i < j) {
for(int l = 0; l < k; l++) {
sb.append(" ");
}
}
}
}
i = j;
list.add(sb.toString());
}
return list;
}
Python版本:
# 文本左右对齐
class Solution:
def fullJustify(self, words: list, maxWidth: int) -> list:
res = list()
n = len(words)
i, j, blank = 0, 0, 0
while i < n:
curlen = maxWidth
count = 0
blank = 0
# 求出一行能放的单词数
while j < n and curlen >= len(words[j]):
curlen -= len(words[j])
count += 1
blank += 1
curlen -= 1
j += 1
blank += curlen
arr = str()
if j >= n or count == 1:
while i < j:
arr += words[i] + ' '
i += 1
arr = arr.strip()
while len(arr) < maxWidth:
arr += " "
else:
mod = blank % (count - 1)
ans = blank // (count - 1)
while i < j:
arr += words[i]
i += 1
k = ans + 1 if mod > 0 else ans
mod -= 1
if i < j:
for l in range(0, k):
arr += " "
i = j
res.append(arr)
return res
# 测试
s = Solution()
words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
print(s.fullJustify(words, maxWidth))
# 答案:
['This is an', 'example of text', 'justification. ']
x的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
Java解法:
public static int mySqrt(int x) {
int l = 0, r = x, ans = -1;
while (l <= r){
int mid = (l + r) / 2;
if (mid * mid <= x){
ans = mid;
l = mid + 1;
}else{
r = mid - 1;
}
}
return ans;
}
Python解法:
# x的平方根
class Solution:
def mySqrt(self, x: int) -> int:
l, r, ans = 0, x, -1
while l <= r:
mid = (l + r) // 2
if mid * mid <= x:
ans = mid
l = mid + 1
else:
r = mid - 1
return ans
# 测试
s = Solution()
print(s.mySqrt(5))
# 答案
2
爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
Java解法:
public static int climbStairs(int n) {
if (n == 1 || n == 2){
return n;
}
int a = 1, b = 2, res = 0;
for (int i = 3 ; i <= n ; i++){
res = a + b;
a = b;
b = res;
}
return res;
}
Python解法:
# 爬楼梯
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1 or n == 2:
return n
i, j, res = 1, 2, 0
for k in range(3, n+1):
res = i + j
i = j
j = res
return res
# 测试
s = Solution()
print(s.climbStairs(5))
# 测试
8
简化路径
以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分
Java解法:
/*
使用split将字符分开后,要么得到空格,要么得到字符,要么得到..或是.
使用栈模拟,遍历字符数组,如果是正常字符,就栈入,如果是..则弹出,如果是.或是空则continue
最后遍历栈,将字符拼接在一起返回即可
*/
public static String simplifyPath(String path) {
Stack<String> stack = new Stack<>();
String []pathArr = path.split("/");
for (int i = 0 ; i < pathArr.length; i++){
if (pathArr[i].length() == 0|| pathArr[i].equals(".")){
continue;
}
if (!stack.isEmpty()){
if (pathArr[i].equals("..")){
stack.pop();
}else{
stack.push(pathArr[i]);
}
}else{
if(!pathArr[i].equals("..")){
stack.push(pathArr[i]);
}
}
}
StringBuilder res = new StringBuilder();
if(stack.isEmpty()) {
return res.append('/').toString();
}
while (!stack.isEmpty()){
res.insert(0,stack.pop());
res.insert(0,'/');
}
return res.toString();
}
Python解法:
# 简化路径
# 将字符串解析成列表,分隔符/,去掉''和.;
# 对..分情况处理:
# 1)当..不在首部,将..及其前一个元素去除
# 2)当..在首部,只将..去除
class Solution:
def simplifyPath(self, path: str) -> str:
# 拆成列表,且不能为''和'.'
pathArr = [p for p in path.split('/') if p not in ['', '.']]
while '..' in pathArr:
idx = pathArr.index('..')
if idx != 0:
pathArr = pathArr[:idx - 1] + pathArr[idx+1:]
else:
pathArr.remove("..")
res = '/'+'/'.join(pathArr)
return res
# 测试
s = Solution()
path = "/a/./b/../../c/"
print(s.simplifyPath(path))
# 测试
/c
编辑距离
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
Java解法:
/*
动态规划
用 dp[i][j] 表示 A 的前 i 个字母和 B 的前 j 个字母之间的编辑距离。
当我们获得 dp[i][j-1],dp[i-1][j] 和 dp[i-1][j-1] 的值之后就可以计算出 dp[i][j]。
dp[i][j-1] 为 A 的前 i 个字符和 B 的前 j - 1 个字符编辑距离的子问题。
即对于 B 的第 j 个字符,我们在 A 的末尾添加了一个相同的字符,那么 dp[i][j] 最小可以为 dp[i][j-1] + 1;
dp[i-1][j] 为 A 的前 i - 1 个字符和 B 的前 j 个字符编辑距离的子问题。
即对于 A 的第 i 个字符,我们在 B 的末尾添加了一个相同的字符,那么 dp[i][j] 最小可以为 dp[i-1][j] + 1;
dp[i-1][j-1] 为 A 前 i - 1 个字符和 B 的前 j - 1 个字符编辑距离的子问题。
即对于 B 的第 j 个字符,我们修改 A 的第 i 个字符使它们相同,那么 dp[i][j] 最小可以为 dp[i-1][j-1] + 1。
特别地,如果 A 的第 i 个字符和 B 的第 j 个字符原本就相同,那么我们实际上不需要进行修改操作。在这种情况下,dp[i][j] 最小可以为 dp[i-1][j-1]
对于边界情况,一个空串和一个非空串的编辑距离为 D[i][0] = i 和 D[0][j] = j,D[i][0]
相当于对 word1 执行 i 次删除操作,D[0][j] 相当于对 word1执行 j 次插入操作
*/
public int minDistance(String word1, String word2) {
int n = word1.length();
int m = word2.length();
/* 有一个字符串为空串 */
if (n * m == 0) {
return n + m;
}
/* DP 数组 */
int[][] dp = new int[n + 1][m + 1];
/* 边界状态初始化 */
for (int i = 0; i < n + 1; i++) {
dp[i][0] = i;
}
for (int j = 0; j < m + 1; j++) {
dp[0][j] = j;
}
/* 计算所有 dp 值 */
for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < m + 1; j++) {
int res1 = dp[i - 1][j] + 1;
int res2 = dp[i][j - 1] + 1;
int res3 = dp[i - 1][j - 1];
if (word1.charAt(i - 1) != word2.charAt(j - 1)) {
res3 += 1;
}
dp[i][j] = Math.min(res1, Math.min(res2, res3));
}
}
return dp[n][m];
}
Python解法:
# 编辑距离
# 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
if m == 0 or n == 0:
return n + m;
# 创建dp数组,初始化
dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = i
for j in range(n + 1):
dp[0][j] = j
# 计算
for i in range(1, m+1):
for j in range(1, n+1):
res1 = dp[i-1][j] + 1
res2 = dp[i][j-1] + 1
res3 = dp[i-1][j-1]
if word1[i-1] != word2[j-1]:
res3 += 1
dp[i][j] = min(res1, min(res2, res3))
return dp[m][n]
# 测试
s = Solution()
word1 = "horse"
word2 = "ros"
print(s.minDistance(word1, word2))
# 答案:
3
最小编辑距离
给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。
示例1
输入
“abc”,“adc”,5,3,2
返回值
2
/*
dp[i][j] 表示 word1[0~i] 变成 word2[0~j] 需要的操作次数
*/
public static int minEditCost (String str1, String str2, int ic, int dc, int rc) {
// write code here
// 如果有一个其中为空
if (str1 == null){
return str2.length() * ic;
}
if (str2 == null){
return str1.length() * dc;
}
int m = str1.length(), n = str2.length();
// dp[0][0] 表示空字符串变成空字符串的代价(0)
int[][] dp = new int[m + 1][n + 1];
// 由 str1 变成空字符串的代价
for (int i = 1; i <= m; i++){
dp[i][0] = i * dc;
}
// 由空字符串变成 str2 的代价
for (int j = 1; j <= n; j++){
dp[0][j] = j *ic;
}
for (int i = 1; i <= m; i++){
for (int j = 1; j <= n; j++){
int cur1 = dp[i-1][j] + dc; //dp[i-1][j] 为 dp[i][j] 删除一个元素变成 dp[i-1][j],即加上dc
int cur2 = dp[i][j-1] + ic;
int cur3 = dp[i-1][j-1];
if (str1.charAt(i-1) != str2.charAt(j-1)){
cur3 += rc;
}
dp[i][j] = Math.min(Math.min(cur1, cur2), cur3);
}
}
return dp[m][n];
}
矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。
Java解法:
public static void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean row = false, col = false;
/*判断第一行、列有无0*/
for (int j = 0 ; j < n ; j++) {
if (matrix[0][j] == 0){
row = true;
break;
}
}
for (int i = 0 ; i < m ; i++) {
if (matrix[i][0] == 0){
col = true;
break;
}
}
/*把第一行和第一列作为 标志位,对应第一行和列被标志了,后续行、列需要置位0*/
for (int i = 1 ; i < m ; i++){
for (int j = 1 ; j < n ; j++){
if (matrix[i][j] == 0){
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
/*置零*/
for (int i = 1 ; i < m ; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0){
matrix[i][j] = 0;
}
}
}
/*对最先的第一行,列做处理*/
if (row){
for (int j = 0 ; j < n ; j++){
matrix[0][j] = 0;
}
}
if (col){
for (int i = 0 ; i < m ; i++){
matrix[i][0] = 0;
}
}
}
Python解法:
# 矩阵置零
class Solution:
def setZeroes(self, matrix: list) -> list:
m, n = len(matrix), len(matrix[0])
row, col = False, False
# 找第一行是否有0
for j in range(n):
if matrix[0][j] == 0:
row = True
break
# 找第一列是否有0
for i in range(m):
if matrix[i][0] == 0:
col = True
break
# 把第一行和第一列作为 标志位,对应第一行和列被标志了,后续行、列需要置位0
for i in range(1, m):
for j in range(1, n):
if matrix[i][j] == 0:
matrix[i][0] = matrix[0][j] = 0
# 置0
for i in range(1, m):
for j in range(1, n):
if matrix[i][0] == 0 or matrix[0][j] == 0:
matrix[i][j] = 0
# 对最先的第一行,列做处理
if row:
for j in range(n):
matrix[0][j] = 0
if col:
for i in range(m):
matrix[i][0] = 0
return matrix
# 测试
s = Solution()
matrix = [
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
print(s.setZeroes(matrix))
# 答案:
[[0, 0, 0, 0], [0, 4, 5, 0], [0, 3, 1, 0]]
进制转换
给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数
示例1
输入
7,2
返回值
“111”
备注:
M是32位整数,2<=N<=16.
public static String solve (int M, int N) {
// write code here
StringBuilder res = new StringBuilder("");
String []arr = {
"A","B","C","D","E","F"};
boolean flag = false;
if (M < 0){
M = -M;
flag = true;
}
while(M != 0){
int val = M % N;
if (val < 10){
res.append(val);
}else{
res.append(arr[val - 10]);
}
M /= N;
}
if (flag){
return res.append("-").reverse().toString();
}else{
return res.reverse().toString();
}
}