给出两个?非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照?逆序?的方式存储的,并且它们的每个节点只能存储?一位?数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0?开头。
水题
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
ListNode listNode = head;
while (l1 != null || l2 != null){
if (l1 != null){
listNode.val += l1.val;
l1 = l1.next;
}
if (l2 != null){
listNode.val += l2.val;
l2 = l2.next;
}
if (listNode.val > 9 || l1 != null || l2 != null) {
listNode.next = new ListNode(listNode.val / 10);
listNode.val %= 10;
listNode = listNode.next;
}
}
return head;
}
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
水题,窗口
public int lengthOfLongestSubstring(String s) {
int []count = new int[300];
int left = 0,right = 0,ans = 0;
Arrays.fill(count,0);
while(right < s.length()){
right = Integer.max(right,left);
while(right < s.length() &&count[s.charAt(right)] == 0) {
count[s.charAt(right)]++;
right++;
}
ans = Integer.max(ans,right-left);
while(right < s.length() &&count[s.charAt(right)] != 0){
count[s.charAt(left)]--;
left++;
}
}
return ans;
}
给定两个大小为 m 和 n 的正序(从小到大)数组?nums1 和?nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为?O(log(m + n))。
你可以假设?nums1?和?nums2?不会同时为空。
public int findKth(int[] nums1, int start1,int[] nums2,int start2,int k){
if (nums1.length-start1 < nums2.length-start2)//让nums1数组的长度始终最大
return findKth(nums2,start2,nums1,start1,k);
if (nums2.length == start2)//当nums2数组为空时,直接选择nums1数组
return nums1[start1+k-1];
if (k == 1)//需要第1小的元素时,直接选择两数组的最小值
return Integer.min(nums1[start1],nums2[start2]);
int i = Integer.min(nums1.length-1,start1+(k>>1)-1);//防止出现越界情况
int j = Integer.min(nums2.length-1, start2+(k>>1)-1);
return nums1[i] < nums2[j]
? findKth(nums1,i+1,nums2,start2,k - (i - start1 + 1))
: findKth(nums1,start1,nums2,j+1,k - (j - start2 + 1));
}
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int sum = nums1.length+nums2.length+1;//需要加1,例如总数组长度为3,则中位数是第2个,(3+1)/2 = 2
double ans1 = findKth(nums1,0,nums2,0,(sum>>1));
if (sum %2 == 1)//当sum为奇数时,说明总数组长度为偶数,所以需要两个数
ans1 = (ans1 + findKth(nums1,0,nums2,0,((sum+1)>>1)))*0.5;
return ans1;
}
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
public String longestPalindrome(String s) {
String ans = "";
for(int i = 0;i < s.length()-1;i++){
String temp1 = s.charAt(i) == s.charAt(i+1) ? check(s,i,i+1) :"";
String temp2 = check(s,i,i);
ans = temp1.length() > ans.length()? temp1 : ans;
ans = temp2.length() > ans.length()? temp2 : ans;
}
return s.length() == 1? s : ans;
}
public String check(String s,int l,int r){
while (l-1 >= 0 && r+1 < s.length() &&s.charAt(l-1) == s.charAt(r+1)){
l--;
r++;
}
return s.substring(l,r+1);
}
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
模拟移动顺序,原字符串从左到右移动,相对于Z字形来说则是从上到下依次移动。
public String convert(String s, int numRows) {
if (numRows == 1) return s;
List<StringBuilder> list = new ArrayList<>();
int go = 1,now = 0;
StringBuilder ans = new StringBuilder();
for(int i = Integer.min(numRows,s.length());i >= 0;i--)
list.add(new StringBuilder());
for(char i : s.toCharArray()){
list.get(now).append(i);
now += go;
if (now == 0 || now == numRows -1) go = -1*go;
for (StringBuilder i : list)
ans.append(i);
return ans.toString();
}
给你一个字符串?s?和一个字符规律?p,请你来实现一个支持 ‘.‘?和?‘‘?的正则表达式匹配。
‘.‘ 匹配任意单个字符
‘‘ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖?整个?字符串?s的,而不是部分字符串。
public boolean isMatch(String s, String p) {
if (p.isEmpty()) return s.isEmpty();
boolean flag = !s.isEmpty()
&& (s.charAt(0) == p.charAt(0) || p.charAt(0) == ‘.‘);
if (p.length() >= 2 && p.charAt(1) == ‘*‘ ){
return isMatch(s,p.substring(2))
|| (flag && isMatch(s.substring(1),p));
}
return flag && isMatch(s.substring(1),p.substring(1));
}
int dp[][];
public boolean isMatch(String s,String p){
dp = new int[s.length()+10][p.length()+10];
for(int i = 0;i <= s.length();i++)
Arrays.fill(dp[i],-1);
return isMatch(0,0,s,p);
}
public boolean isMatch(int i,int j,String s, String p) {
if (dp[i][j] != -1) return dp[i][j] == 1;
if (p.isEmpty()) return s.isEmpty();
boolean ans ;
boolean flag = !s.isEmpty()
&& (s.charAt(0) == p.charAt(0) || p.charAt(0) == ‘.‘);
if (p.length() >= 2 && p.charAt(1) == ‘*‘ ){
ans = isMatch(i,j+2,s,p.substring(2))
|| (flag && isMatch(i+1,j,s.substring(1),p));
}else {
ans = flag && isMatch(i+1,j+1,s.substring(1),p.substring(1));
}
dp[i][j] = ans ? 1 : 0;
return ans;
}
public boolean isMatch(String s, String p) {
boolean dp[][] = new boolean[s.length() + 5][p.length() + 5];
dp[s.length()][p.length()] = true;
for (int i = s.length(); i >= 0; i--)
for (int j = p.length() - 1; j >= 0; j--) {
boolean flag = i < s.length()
&& (s.charAt(i) == p.charAt(j) || p.charAt(j) == ‘.‘);
if (j + 1 < p.length() && p.charAt(j + 1) == ‘*‘) {
dp[i][j] = dp[i][j + 2] || (flag && dp[i + 1][j]);
} else {
dp[i][j] = flag && dp[i+1][j+1];
}
}
return dp[0][0];
}
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
public ListNode mergeKLists(ListNode[] lists) {
ListNode head = new ListNode(0);
ListNode current = head;
Queue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val-o2.val;
}
});
for(ListNode node : lists)
if (node != null) queue.add(node);
while(!queue.isEmpty()){
ListNode top = queue.poll();
ListNode now = new ListNode(top.val);
if (top.next != null) queue.add(top.next);
current.next = now;
current = now;
}
return head.next;
}
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点?(i,?ai) 。在坐标内画 n 条垂直线,垂直线 i?的两个端点分别为?(i,?ai) 和 (i, 0)。找出其中的两条线,使得它们与?x?轴共同构成的容器可以容纳最多的水。
public int maxArea(int[] height) {
int left = 0,right = height.length-1,ans = 0;
while(left < right){
ans = Integer.max(ans,(right-left+1)*Integer.min(height[left],height[right]));
if (height[right] <= height[left]) right--;
else left++;
}
return ans;
}
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
排序,双指针,时间复杂度\(O(n^2)\),需要注意的是,可能出现重复的三元组,所以需要去重。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ans;
int len = nums.size();
for (int i = 0;i < len-2;i++){
if (i > 0 &&nums[i] == nums[i-1])
continue;
int left = i+1, right = len-1;
while(left < right){
int now = nums[i] + nums[left] + nums[right];
if (now == 0 ){
if (ans.empty() ||ans[ans.size()-1][0] != nums[i] || ans[ans.size()-1][1] != nums[left] || ans[ans.size()-1][2] != nums[right])
ans.push_back(vector<int>({nums[i],nums[left],nums[right]}));
left++;
right--;
}
else if (now < 0) left++;
else right--;
}
}
return ans;
}
};
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
Arrays.sort(nums);
for(int i = 0;i < nums.length;i++){
if (i != 0 && nums[i-1] == nums[i])//前一个与当前元素相同时直接跳过
continue;
if (nums[i] > 0)
break;
int left = i+1,right = nums.length-1;
while (left < right){
if (nums[i] + nums[left] + nums[right] == 0){
lists.add(Arrays.asList(nums[i],nums[left++],nums[right--]));
while(left < right && left-1 >= 0 && nums[left] == nums[left-1]) left++;
while(left < right && right+1 < nums.length && nums[right] == nums[right+1]) right--;
}
else if(nums[i] + nums[left] + nums[right] < 0){
left++;
}
else{
right--;
}
}
}
return lists;
}
给定一个包括?n 个整数的数组?nums?和 一个目标值?target。找出?nums?中的三个整数,使得它们的和与?target?最接近。返回这三个数的和。假定每组输入只存在唯一答案。
public int threeSumClosest(int[] nums, int target) {
int ans = Integer.MAX_VALUE;
Arrays.sort(nums);
for (int i = 0; i < nums.length && ans != target; i++) {
int left = i + 1, right = nums.length - 1;
while (left < right) {
int now = nums[i] + nums[left] + nums[right];
if (ans == Integer.MAX_VALUE || Math.abs(target - now) < Math.abs(target - ans)) {
ans = now;
}
if (now < target) {
left++;
} else {
right--;
}
}
}
return ans;
}
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
public int isNthFromEnd(ListNode pre,ListNode head,int n){
int th = head.next == null ? 1
:isNthFromEnd(head,head.next,n)+1;
if (th == n && pre != null){
pre.next = head.next;
}
return th;
}
public ListNode removeNthFromEnd(ListNode head, int n) {
return isNthFromEnd(null,head,n) == n ? head.next : head;
}
给你一个链表,每?k?个节点一组进行翻转,请你返回翻转后的链表。
k?是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是?k?的整数倍,那么请将最后剩余的节点保持原有顺序。
public ListNode reverse(ListNode head){
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
public ListNode reverseKGroup(ListNode head, int k) {
ListNode newHead = new ListNode(0);
newHead.next = head;
ListNode pre = newHead;//表示接下来需要逆转的k个节点的第一个的前面
ListNode end = newHead;//表示接下来需要逆转的k个节点的最后一个
while(end != null){
for(int i = 0;i < k&&end != null;i++)
end = end.next;
if (end == null) break;//如果需要逆转的k个节点的最后一个为null,显然不足k个
ListNode start = pre.next;//k个节点的第一个
ListNode next = end.next;//下一环k节点的第一个
end.next = null;//k个节点的下一个为null,方便reverse
pre.next = reverse(start);//reverse返回逆转后的k个节点的第一个
start.next = next;//逆转后,k个节点的第一个变成了最后一个,此时连接下一环k节点的第一个
pre = end = start;
}
return newHead.next;
}
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
public void nextPermutation(int[] nums) {
int left = nums.length-2;
//从右往左找出第一个顺序的
while(left >= 0){
if (nums[left] < nums[left+1]) break;
left--;
}
//从右往左找出第一个大于left的值,由于前面的阶段,所以保证(left,right]是逆序的
for(int right = nums.length-1;left != -1 && right > left;right--){
if (nums[right] > nums[left]){
swap(nums,left,right);
break;
}
}
//将逆序翻转成顺序
reverse(nums,left+1);
}
public void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public void reverse(int[] nums,int left){
int right = nums.length-1;
while(left < right){
swap(nums,left,right);
left++;
right--;
}
}
给定一个只包含 ‘(‘ 和 ‘)‘ 的字符串,找出最长的包含有效括号的子串的长度。
public int longestValidParentheses(String s) {
int ans = 0;
Stack<Integer> stack = new Stack<>();
stack.push(-1);
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ‘(‘){
stack.push(i);
} else{
stack.pop();
if (stack.isEmpty()){
stack.push(i);
} else{
ans = Integer.max(ans,i - stack.peek());
}
}
}
return ans;
}
public int longestValidParentheses(String s) {
int ans = 0;
int left = 0, right = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ‘(‘) {
left++;
} else {
right++;
}
if (right > left) {
left = right = 0;
} else if (right == left) {
ans = Integer.max(ans, left << 1);
}
}
left = right = 0;
for (int i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == ‘(‘) {
left++;
} else {
right++;
}
if (right < left) {
left = right = 0;
} else if (right == left) {
ans = Integer.max(ans, right << 1);
}
}
return ans;
}
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组?[0,1,2,4,5,6,7]?可能变为?[4,5,6,7,0,1,2]?)。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回?-1?。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是?\(O(log?n)\) 级别。
public int search(int[] nums, int target) {
//左闭右开区间
int left = 0,right = nums.length;
while(left + 1 < right ){
int mid = (left+right) >> 1;
if (target == nums[mid]){
return mid;
} else if (nums[left] <= nums[mid]){
if (target >= nums[left] && target < nums[mid]){
right = mid;
} else{
left = mid;
}
} else {
if (target >= nums[mid] && target <= nums[right-1]){
left = mid;
} else{
right = mid;
}
}
}
return (nums.length != 0 && nums[left] == target) ? left : -1;
}
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
public int firstMissingPositive(int[] nums) {
for (int i = 0; i < nums.length; i++) {
while (nums[i] >= 1 && nums[i] <= nums.length && nums[i] != nums[nums[i] - 1]) {
swap(nums, i , nums[i] - 1);
}
}
for (int i = 0; i < nums.length; i++)
if (nums[i] != i + 1)
return i + 1;
return nums.length + 1;
}
public void swap(int[] nums, int l, int r) {
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
}
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
public int trap(int[] height) {
int ans = 0;
Stack<Integer> stack = new Stack<>();
for(int i = 0;i < height.length; i++) {
while (!stack.empty() && height[i] > height[stack.peek()]) {
int now = stack.pop();
if (stack.empty()) {
continue;
}
int h = Integer.min(height[i], height[stack.peek()]) - height[now];
int l = i - stack.peek() - 1;
ans += h * l;
}
stack.push(i);
}
return ans;
}
public int trap(int[] height) {
int left = 0, right = height.length - 1;
int allSum = 0, allHeight = 0, rowHeight = 1;
while (left <= right) {
while (left <= right && height[left] < rowHeight) {
allHeight += height[left];
left++;
}
while (left < right && height[right] < rowHeight) {
allHeight += height[right];
right--;
}
if (left <= right) {
allSum += right - left + 1;
rowHeight++;
}
}
return allSum - allHeight;
}
给定一个字符串?(s) 和一个字符模式?(p) ,实现一个支持?‘?‘?和?‘‘?的通配符匹配。
‘?‘ 可以匹配任何单个字符。
‘‘ 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
int dp[][] = null;
public boolean isMatch(String s, String p, int startS, int startP) {
if (dp[startS][startP] != -1)
return dp[startS][startP] == 1;
boolean flag = false;
if (startS == s.length() && startP == p.length())
flag = true;
else if (s.length() == startS) {
flag = true;
for (int i = startP; i < p.length(); i++)
if (p.charAt(i) != ‘*‘)
flag = false;
} else if (p.length() == startP)
flag = false;
else if (s.charAt(startS) == p.charAt(startP) || p.charAt(startP) == ‘?‘)
flag = isMatch(s, p, startS + 1, startP + 1);
else if (p.charAt(startP) == ‘*‘) {
flag = isMatch(s, p, startS + 1, startP) || isMatch(s, p, startS, startP + 1);
}
dp[startS][startP] = flag ? 1 : 0;
return flag;
}
public boolean isMatch(String s, String p) {
if (dp == null)
dp = new int[s.length() + 1][p.length() + 1];
for (int i = 0; i < s.length() + 1; i++)
Arrays.fill(dp[i], -1);
return isMatch(s, p, 0, 0);
}
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
x,nums[x] = y,那么就将x+1 ~ x+y加入队列中,其中已经走过的点就跳过int jump(vector<int>& nums) {
queue<int> q;
int visi[nums.size()+5];
memset(visi,0,sizeof(visi));
q.push(0);
while(!q.empty()){
int now = q.front();
q.pop();
for(int i = 1;i <= nums[now] && i+now < nums.size();i++){
if (now+i == nums.size() -1 ) return visi[now]+1;
if (visi[now+i] == 0){
visi[now+i] = visi[now]+1;
q.push(now+i);
}
}
}
return 0;
}
int jump(vector<int>& nums) {
int maxn = 0, ans = 0,end = 0;
for(int i = 0;i < nums.size() - 1 ;i++){
maxn = max(maxn,i+nums[i]);
if (i == end){
end = maxn;
ans++;
}
}
return ans;
}
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
void dfs(int now,vector<int>& nums, vector<vector<int>> &ans){
if (now == nums.size() - 1){
ans.push_back(nums);
return ;
}
for(int i = now;i < nums.size();i++){
swap(nums[now],nums[i]);
dfs(now+1,nums,ans);
swap(nums[now],nums[i]);
}
}
vector<vector<int>> permute(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ans;
dfs(0,nums,ans);
return ans;
}
给定一个可包含重复数字的序列,返回所有不重复的全排列。
void dfs(int now,vector<int>& nums, vector<vector<int>> &ans){
if (now == nums.size() - 1){
ans.push_back(nums);
return ;
}
unordered_set<int> vis;//代码1
for(int i = now;i < nums.size();i++){
if (vis.find(nums[i]) == vis.end()){//代码2
swap(nums[now],nums[i]);
dfs(now+1,nums,ans);
swap(nums[now],nums[i]);
vis.insert(nums[i]);//代码3
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ans;
dfs(0,nums,ans);
return ans;
}
给定一个 n?×?n 的二维矩阵表示一个图像。
将图像顺时针旋转 90 度。
说明:
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for(int i = 0;i < (n>>1);i++){
for(int j = i;j < n - i - 1;j++){
swap(matrix[i][j],matrix[j][n-1-i]);
swap(matrix[i][j],matrix[n-1-i][n-1-j]);
swap(matrix[i][j],matrix[n-1-j][i]);
}
}
return ;
}
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
double myPow(double x, int n) {
double ans = 1;
long long m = n;
if (m < 0){
m = m*-1;
}
while(m){
if (m&1) ans *= x;
m>>=1;;
x *= x;
}
return n < 0 ? 1.0/ans : ans;
}
n?皇后问题研究的是如何将 n?个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给定一个整数 n,返回所有不同的?n?皇后问题的解决方案。
每一种解法包含一个明确的?n 皇后问题的棋子放置方案,该方案中 ‘Q‘ 和 ‘.‘ 分别代表了皇后和空位。
bool row[1005];
bool colm[1005];
bool ele1[3000];
bool ele2[3000];
void change(int x,int y,bool flag,int n){
row[x] = flag;
colm[y] = flag;
ele1[x-y+n] = flag;
ele2[x+y] = flag;
}
void dfs(int x,int y, vector<string> now,vector<vector<string>> &ans,int n){
if (x == n ){
ans.push_back(now);
return ;
}
for(int i= y;i < n;i++){
if (!row[x] && !colm[i] && !ele1[x-i+n] && !ele2[x+i]){
change(x,i,true,n);
string temp = now[x];
now[x] += "Q";
while(now[x].size() < (unsigned int)n) now[x]+=".";
dfs(x+1,0,now,ans,n);
change(x,i,false,n);
now[x] = temp;
}
now[x] += ".";
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> ans;
vector<string> now;
memset(row,false,sizeof(row));
memset(colm,false,sizeof(colm));
memset(ele1,false,sizeof(ele1));
memset(ele2,false,sizeof(ele2));
for(int i = 0;i < n;i++)
now.push_back("");
dfs(0,0,now,ans,n);
return ans;
}
n?皇后问题研究的是如何将 n?个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给定一个整数 n,返回 n 皇后不同的解决方案的数量。
int ans;
bool row[1005];
bool colm[1005];
bool ele1[3000];
bool ele2[3000];
void change(int x,int y,bool flag,int n){
row[x] = flag;
colm[y] = flag;
ele1[x-y+n] = flag;
ele2[x+y] = flag;
}
void dfs(int x,int y,int n){
if (x == n ){
ans++;
return ;
}
for(int i= y;i < n;i++){
if (!row[x] && !colm[i] && !ele1[x-i+n] && !ele2[x+i]){
change(x,i,true,n);
dfs(x+1,0,n);
change(x,i,false,n);
}
}
}
int totalNQueens(int n) {
ans = 0;
memset(row,false,sizeof(row));
memset(colm,false,sizeof(colm));
memset(ele1,false,sizeof(ele1));
memset(ele2,false,sizeof(ele2));
dfs(0,0,n);
return ans;
}
给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new LinkedList<>();
if (matrix.length == 0) return list;
int left = 0,right = matrix[0].length-1;
int up = 0,down = matrix.length-1;
while(left <= right && up <= down){
for(int i = left;i <= right;i++)
list.add(matrix[up][i]);
for(int i = up+1;i <= down;i++)
list.add(matrix[i][right]);
if (left < right && up < down) {
for (int i = right - 1; i >= left; i--)
list.add(matrix[down][i]);
for (int i = down - 1; i >= up + 1; i--)
list.add(matrix[i][left]);
}
left++;
up++;
down--;
right--;
}
return list;
}
maxn >= len-1时可以提前returnbool canJump(vector<int>& nums) {
int len = nums.size();
int maxn = 0;
for(int i = 0;i < len && i <= maxn;i++){
maxn = max(maxn,i+nums[i]);
}
return maxn >= len-1;
}
给出一个区间的集合,请合并所有重叠的区间。
vector<vector<int>> merge(vector<vector<int>>& intervals) {
int n = intervals.size();
vector<vector<int>> ans ;
if (n == 0) return ans;
sort(intervals.begin(),intervals.end());
int left = intervals[0][0],right = intervals[0][1];
for(int i = 1;i < n;i++){
if ( intervals[i][0] > right ){
ans.push_back({left,right});
left = intervals[i][0];
right = intervals[i][1];
}
else{
right = max(right,intervals[i][1]);
}
}
ans.push_back({left,right});
return ans;
}
给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
Hard级别class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
if (intervals.empty()){
return vector<vector<int>>({newInterval});
}
else if (newInterval.empty()){
return intervals;
}
int n = intervals.size();
int left = newInterval[0],right = newInterval[1];
bool flag = true;
vector<vector<int>> ans;
for(int i = 0;i < n;i++){
if (intervals[i][1] < left || intervals[i][0] > right){
if (intervals[i][0] > right && flag){
ans.push_back({left,right});
flag = false;
}
ans.push_back(intervals[i]);
}
else{
left = min(left,intervals[i][0]);
right = max(right,intervals[i][1]);
}
if (i == n-1 && flag){
ans.push_back({left,right});
}
}
return ans;
}
};
给出集合?[1,2,3,…,n],其所有元素共有?n! 种排列。
按大小顺序列出所有排列情况,并一一标记。
给定?n 和?k,返回第?k?个排列。
当?n = 3 时, 所有排列如下:
- "123"
- "132"
- "213"
- "231"
- "312"
- "321"
int A(int n){
int ans = 1;
while(n > 0){
ans *= n--;
}
return ans ;
}
void delete_i(int n,int k,char nums[]){
for(int i = k;i < n-1;i++)
nums[i] = nums[i+1];
}
string getPermutation(int n, int k) {
string ans = "";
char nums[20];
for(int i = 0;i < n;i++)
nums[i] = ‘1‘+i;
k--;
for(int i = 0;i < n;i++){
int factor = A(n - i - 1);
int pre = k/factor;
k %= factor;
ans += nums[pre];
delete_i(n-i,pre,nums);
}
return ans;
}
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
{1,2,3,4,5},k = 2,将链表分成{{1,2,3},{4,5}}{{4,5},{1,2,3}}public ListNode rotateRight(ListNode head, int k) {
if (head == null || head.next == null)
return head;
ListNode temp = head;
int len = 0;
while(temp != null){
len++;
temp = temp.next;
}
k %= len;
if (k == 0)
return head;
ListNode nowHead = head;
while(--len != k){
nowHead = nowHead.next;
}
ListNode newHead = nowHead.next;
nowHead.next = null;
temp = newHead;
while(temp.next != null){
temp = temp.next;
}
temp.next = head;
return newHead;
}
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
m+n-2,那么我们只要在(m+n-2)个数中取出m-1(或者n-1)个表示向右走,那么剩下的就是向下走了。给你两个单词?word1 和?word2,请你计算出将?word1?转换成?word2 所使用的最少操作数?。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
public int minDistance(String word1, String word2) {
//dp[i][j]表示word1的前i个组成word2的前j个的最少操作多少操作
int dp[][] = new int[word1.length() + 1][word2.length() + 1];
//当word1或word2为0时,需要添加/删除对方Word的长度
for (int i = 0; i <= word1.length(); i++)
dp[i][0] = i;
for (int j = 0; j <= word2.length(); j++)
dp[0][j] = j;
for (int i = 1; i <= word1.length(); i++) {
for (int j = 1; j <= word2.length(); j++) {
dp[i][j] = (word1.charAt(i - 1) == word2.charAt(j - 1) ? dp[i - 1][j - 1]
: (1 + Integer.min(dp[i - 1][j - 1], Integer.min(dp[i][j - 1], dp[i - 1][j]))));
}
}
return dp[word1.length()][word2.length()];
}
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
public void setZeroes(int[][] matrix) {
boolean isRow = false;
boolean isColm = false;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (i == 0 && matrix[i][j] == 0)
isRow = true;
if (j == 0 && matrix[i][j] == 0)
isColm = true;
if (matrix[i][j] == 0)
matrix[i][0] = matrix[0][j] = 0;
}
}
for (int i = 1; i < matrix.length; i++) {
for (int j = 1; j < matrix[i].length; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0)
matrix[i][j] = 0;
}
}
if (isRow) {
for (int i = 0; i < matrix[0].length; i++)
matrix[0][i] = 0;
}
if (isColm) {
for (int i = 0; i < matrix.length; i++)
matrix[i][0] = 0;
}
}
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
public boolean check(Map<Character,Integer> map){
for(Integer value : map.values()){
if (value > 0)
return false;
}
return true;
}
public String minWindow(String s, String t) {
String ans = "";
int left = -1,right = 0;//左开右开区间
Map<Character,Integer> map = new HashMap<>();
for(int i = 0;i < t.length();i++){
if (map.containsKey(t.charAt(i))) {
map.put(t.charAt(i), map.get(t.charAt(i)) + 1);
} else {
map.put(t.charAt(i), 1);
}
}
while (right < s.length()){
while(right < s.length() && !check(map)){
if (map.containsKey(s.charAt(right)) ){
map.put(s.charAt(right),map.get(s.charAt(right))-1);
}
right++;
}
while(left < right && check(map)){
if (right > left && (ans.equals("") || ans.length() > right-left)){
ans = s.substring(left+1,right);
}
left++;
if (map.containsKey(s.charAt(left))){
map.put(s.charAt(left),map.get(s.charAt(left))+1);
}
}
}
return ans;
}
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
List<List<Integer>> ans ;
void dfs(List<Integer> cur,int now,int n,int k){
if (k == 0) ans.add(new ArrayList<>(cur));
for(int i = now+1;i <= n;i++){
cur.add(i);
dfs(cur,i,n,k-1);
cur.remove(cur.size()-1);
}
}
public List<List<Integer>> combine(int n, int k) {
ans = new ArrayList<List<Integer>>();
dfs(new ArrayList<Integer>(),0,n,k);
return ans;
}
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
public class code78 {
List<List<Integer>> ans;
void dfs(List<Integer> cur, int now, int[] nums) {
ans.add(new ArrayList<>(cur));
for (int i = now + 1; i < nums.length; i++) {
cur.add(nums[i]);
dfs(cur, i, nums);
cur.remove(cur.size() - 1);
}
}
public List<List<Integer>> subsets(int[] nums) {
ans = new ArrayList<>();
dfs(new ArrayList<>(), -1, nums);
return ans;
}
}
public int removeDuplicates(int[] nums) {
int left = 1,right = 1,cnt = 1;
while(right < nums.length){
if (nums[right] == nums[right-1]){
cnt++;
}
else{
cnt = 1;
}
if (cnt <= 2){
nums[left++] = nums[right];
}
right++;
}
return left;
}
public boolean search(int[] nums, int target) {
int left = 0,right = nums.length - 1;
while(left <= right){
int mid = (left+right)>>1;
if (target == nums[mid])
return true;
if (nums[left] == nums[mid])//特例只能+1
left++;
else if (nums[left] <= nums[mid]){
if (target >= nums[left] && target < nums[mid])
right = mid - 1;
else
left = mid + 1;
}
else{
if (target > nums[mid] && target <= nums[right])
left = mid + 1;
else
right = mid - 1;
}
}
return false;
}
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
Medium难度,但可以看作Easypublic ListNode deleteDuplicates(ListNode head) {
if (head == null)
return head;
ListNode newHead = new ListNode(0);
ListNode nowNode = newHead;
while(head != null){
while (head != null && head.next != null && head.val == head.next.val){
int nowVal = head.val;
while(head != null && head.val == nowVal)
head = head.next;
}
nowNode.next = head;
nowNode = nowNode.next;
head = (head == null ? null :head.next);
}
return newHead.next;
}
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
public int largestRectangleArea(int[] heights) {
int ans = 0;
int[] newHeights = new int[heights.length+2];
Deque<Integer> stack = new ArrayDeque<>();
for(int i = 0;i < newHeights.length;i++)
newHeights[i] = (i == 0 || i == newHeights.length-1)? 0 : heights[i-1];
for(int i = 0;i < newHeights.length;i++){
while (!stack.isEmpty() && newHeights[stack.getLast()] > newHeights[i]){
int h = newHeights[stack.pollLast()];
ans = Integer.max(ans,h*(i - stack.getLast() - 1));
}
stack.addLast(i);
}
return ans;
}
给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
public int largestRectangleArea(int[] heights) {
int ans = 0;
int[] newHeights = new int[heights.length+2];
Deque<Integer> stack = new ArrayDeque<>();
for(int i = 0;i < newHeights.length;i++)
newHeights[i] = (i == 0 || i == newHeights.length-1)? 0 : heights[i-1];
for(int i = 0;i < newHeights.length;i++){
while (!stack.isEmpty() && newHeights[stack.getLast()] > newHeights[i]){
int h = newHeights[stack.pollLast()];
ans = Integer.max(ans,h*(i - stack.getLast() - 1));
}
stack.addLast(i);
}
return ans;
}
public int maximalRectangle(char[][] matrix) {
if (matrix.length == 0)
return 0;
int[] dp = new int[matrix[0].length];
Arrays.fill(dp,0);
int ans = 0;
for(int i = 0;i < matrix.length;i++){
for(int j = 0;j < matrix[i].length;j++){
dp[j] = (matrix[i][j] == ‘1‘ ? dp[j]+1: 0);
}
ans = Integer.max(ans,largestRectangleArea(dp));
}
return ans;
}
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
class Solution {
List<List<Integer>> ans;
void dfs(int[] nums,int now,List<Integer> cur){
ans.add(new ArrayList(cur));
for(int i = now;i < nums.length;i++){
if (i == now || nums[i] != nums[i-1] ){
cur.add(nums[i]);
dfs(nums,i+1,cur);
cur.remove(cur.size()-1);
}
}
}
public List<List<Integer>> subsetsWithDup(int[] nums) {
ans = new ArrayList<>();
Arrays.sort(nums);
dfs(nums,0,new ArrayList<>());
return ans;
}
}
一条包含字母?A-Z 的消息通过以下方式进行了编码,给定一个只包含数字的非空字符串,请计算解码方法的总数。
- ‘A‘ -> 1
- ‘B‘ -> 2
- ...
- ‘Z‘ -> 26
public int numDecodings(String s) {
if (s.charAt(0) == ‘0‘)
return 0;
int pre = 1,now = 1;
for(int i = 1;i < s.length();i++){
int temp = now;
if (s.charAt(i) == ‘0‘){
if (s.charAt(i - 1) != ‘1‘ && s.charAt(i - 1) != ‘2‘ )
return 0;
else now = pre;
}
else if (s.charAt(i - 1) == ‘1‘ || (s.charAt(i - 1) == ‘2‘ && s.charAt(i) >= ‘1‘ && s.charAt(i) <= ‘6‘))
now += pre;
pre = temp;
}
return now;
}
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
public ListNode reverseBetween(ListNode head, int m, int n) {
int k = 1;
ListNode newHead = new ListNode(0);
ListNode temp = newHead;
while(head != null && k != m){//先查找到需要反转的起点
temp.next = head;
temp = head;
head = head.next;
k++;
}
ListNode end = head;//起点是反转链表的终点
ListNode start = null;
ListNode pre = null;
while(head != null && k != n+1){//一直遍历到反转链表的下一节点
if (k == n) //当遍历到反转链表的终点时,作为起点连接
temp.next = head;
ListNode nextNode = head.next;
head.next = pre;
pre = head;
head = nextNode;
k++;
}
end.next = head;
return newHead.next;
}
给定一个二叉树,返回它的中序 遍历。
要求:迭代
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null)
stack.add(root);
while(!stack.empty()){
TreeNode node = stack.pop();
if (node.left == null && node.right == null){
list.add(node.val);
continue;
}
if (node.right != null)
stack.push(node.right);
stack.push(node);
if (node.left != null)
stack.push(node.left);
node.left = node.right = null;
}
return list;
}
原文:https://www.cnblogs.com/MMMMMMMW/p/13181553.html