实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-permutation
本质上这种题有两种情况:
(1):如果是降序数组,则下一个排列数字为最小数字,即将数组全部反转即可;
(2):一般情况,首先定义两个index1和index2指针用于保存左右要交换的数字,首先从后往前遍历,
得到第一次的nums[i - 1] < nums[i],将下标保存分别赋值index1=i-1,index2=i,
(如果遍历完后index还是等于-1,即数组为降序数组,直接反转数组即可),而index2不一定是当前下标,
需要从i=index2到数组末尾继续遍历,如果nums[i] > nums[index1]就继续遍历赋值,
最后反转index1 + 1到数组末尾的数字即可得到下一个排列;
class Solution {
public void nextPermutation(int[] nums) {
int index1 = -1, index2 = -1;
for (int i = nums.length - 1; i > 0; i--) {
if (nums[i] > nums[i - 1]) {
index1 = i - 1;
index2 = i;
break;
}
}
if (index1 == -1) {
int start = 0, end = nums.length - 1;
while (start < end) {
int temp = nums[start];
nums[start++] = nums[end];
nums[end--] = temp;
}
return;
}
for (int i = index2; i < nums.length; i++) {
if (nums[i] > nums[index1])
index2 = i;
}
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
int start = index1 + 1, end = nums.length - 1;
while (start < end) {
int tem = nums[start];
nums[start++] = nums[end];
nums[end--] = tem;
}
}
}
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [3,2,1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-postorder-traversal
递归方式
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<Integer> list = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {
post(root);
return list;
}
public void post(TreeNode root){
if(root == null){
return ;
}
postorderTraversal(root.left);
postorderTraversal(root.right);
list.add(root.val);
}
}
迭代方式求二叉树后序遍历可以如下操作
用stack存储当前节点的左右子树,output保存输出当前节点, 结束后对output在进行翻转
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<TreeNode> stack = new LinkedList<>();
LinkedList<Integer> output = new LinkedList<>();
if (root == null) {
return output;
}
stack.add(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pollLast();
output.addFirst(node.val);
if (node.left != null) {
stack.add(node.left);
}
if (node.right != null) {
stack.add(node.right);
}
}
return output;
}
}
写一个程序,输出从 1 到 n 数字的字符串表示。
1. 如果 n 是3的倍数,输出“Fizz”;
2. 如果 n 是5的倍数,输出“Buzz”;
3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。
示例:
n = 15,
返回:
[
"1",
"2",
"Fizz",
"4",
"Buzz",
"Fizz",
"7",
"8",
"Fizz",
"Buzz",
"11",
"Fizz",
"13",
"14",
"FizzBuzz"
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fizz-buzz
class Solution {
public List<String> fizzBuzz(int n) {
List<String> list = new ArrayList<>();
for (int i = 1; i <= n; i++) {
StringBuilder sb = new StringBuilder();
if(i % 3 == 0 ){
sb.append("Fizz");
}
if(i %5 == 0){
sb.append("Buzz");
}
if(sb.toString().equals("")){
sb.append(i);
}
list.add(sb.toString());
}
return list;
}
}
给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。
删除完毕后,请你返回最终结果链表的头节点。
你可以返回任何满足题目要求的答案。
(注意,下面示例中的所有序列,都是对 ListNode 对象序列化的表示。)
示例 1:
输入:head = [1,2,-3,3,1]
输出:[3,1]
提示:答案 [1,2,1] 也是正确的。
示例 2:
输入:head = [1,2,3,-3,4]
输出:[1,2,4]
示例 3:
输入:head = [1,2,3,-3,-2]
输出:[1]
提示:
给你的链表中可能有 1 到 1000 个节点。
对于链表中的每个节点,节点的值:-1000 <= node.val <= 1000.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-zero-sum-consecutive-nodes-from-linked-list
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
/*
我们可以考虑如果给的入参不是链表是数组的话,只需要求出前缀和,对于前缀和相同的项,
那他们中间的部分即是可以消除掉的,比如以 [1, 2, 3, -3, 4] 为例,
其前缀和数组为 [1, 3, 6, 3, 7]
,我们发现有两项均为 3,则 6 和 第二个 3 所对应的原数组中的数字是可以消掉的。换成链表其实
也是一
样的思路,把第一个 3 的 next 指向第二个 3 的 next 即可
*/
public ListNode removeZeroSumSublists(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
Map<Integer, ListNode> prefixSumMap = new HashMap<>();
ListNode p = dummy;
int prefixSum = 0;
while (p != null) {
prefixSum += p.val;
if (prefixSumMap.containsKey(prefixSum)) {
p = prefixSumMap.get(prefixSum).next;
int val = prefixSum + p.val;
while (val != prefixSum) {
//以下代码是删去 两个前缀和相同的结点之间的结点,
//不然会导致之后可能某些结点的前缀和错误匹配了本应该被删去的节点
prefixSumMap.remove(val);
p = p.next;
val += p.val;
}
prefixSumMap.get(prefixSum).next = p.next;
}
else {
prefixSumMap.put(prefixSum, p);
}
p = p.next;
}
return dummy.next;
}
}
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-string
class Solution {
public void reverseString(char[] s) {
for (int i = 0,j = s.length-1; i < j; i++,j--) {
char temp = s[i];
s[i]= s[j];
s[j] = temp;
}
}
}
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
一次遍历算法
首先我们将添加一个哑结点作为辅助,该结点位于列表头部。哑结点用来简化某些极端情况,例如列表中只含有一个结点,或需要删除列表的头部。
上述算法可以优化为只使用一次遍历。我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1 步,而第二个指针将从列表的开头出发。现在,这两个指针被 n 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 n个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。
删除链表的倒数第 N 个元素
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode first = dummy;
ListNode second = dummy;
for (int i = 1; i <= n + 1; i++) {
first = first.next;
}
while (first != null) {
first = first.next;
second = second.next;
}
second.next = second.next.next;
return dummy.next;
}
}