Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1b55387

Browse filesBrowse files
committed
Deploying to main from @ 796c013 🚀
1 parent 7d64013 commit 1b55387
Copy full SHA for 1b55387
Expand file treeCollapse file tree

24 files changed

+1056
-49
lines changed

‎plan/contest_list.md

Copy file name to clipboardExpand all lines: plan/contest_list.md
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ headerDepth: 0
408408
| 题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
409409
| :------: | :------ | :------: | :------ | :------: | :------: |
410410
| 3151 | 特殊数组 I | | [`数组`](/tag/array.md) | 🟢 | [🀄️](https://leetcode.cn/problems/special-array-i) [🔗](https://leetcode.com/problems/special-array-i) |
411-
| 3152 | 特殊数组 II | | [`数组`](/tag/array.md) [`二分查找`](/tag/binary-search.md) [`前缀和`](/tag/prefix-sum.md) | 🟠 | [🀄️](https://leetcode.cn/problems/special-array-ii) [🔗](https://leetcode.com/problems/special-array-ii) |
411+
| 3152 | 特殊数组 II | [[✓]](/problem/3152.md) | [`数组`](/tag/array.md) [`二分查找`](/tag/binary-search.md) [`前缀和`](/tag/prefix-sum.md) | 🟠 | [🀄️](https://leetcode.cn/problems/special-array-ii) [🔗](https://leetcode.com/problems/special-array-ii) |
412412
| 3153 | 所有数对中数位差之和 | | [`数组`](/tag/array.md) [`哈希表`](/tag/hash-table.md) [`数学`](/tag/math.md) `1+` | 🟠 | [🀄️](https://leetcode.cn/problems/sum-of-digit-differences-of-all-pairs) [🔗](https://leetcode.com/problems/sum-of-digit-differences-of-all-pairs) |
413413
| 3154 | 到达第 K 级台阶的方案数 | | [`位运算`](/tag/bit-manipulation.md) [`记忆化搜索`](/tag/memoization.md) [`数学`](/tag/math.md) `2+` | 🔴 | [🀄️](https://leetcode.cn/problems/find-number-of-ways-to-reach-the-k-th-stair) [🔗](https://leetcode.com/problems/find-number-of-ways-to-reach-the-k-th-stair) |
414414

@@ -1200,7 +1200,7 @@ headerDepth: 0
12001200
| 题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
12011201
| :------: | :------ | :------: | :------ | :------: | :------: |
12021202
| 2778 | 特殊元素平方和 | | [`数组`](/tag/array.md) [`枚举`](/tag/enumeration.md) | 🟢 | [🀄️](https://leetcode.cn/problems/sum-of-squares-of-special-elements) [🔗](https://leetcode.com/problems/sum-of-squares-of-special-elements) |
1203-
| 2779 | 数组的最大美丽值 | | [`数组`](/tag/array.md) [`二分查找`](/tag/binary-search.md) [`排序`](/tag/sorting.md) `1+` | 🟠 | [🀄️](https://leetcode.cn/problems/maximum-beauty-of-an-array-after-applying-operation) [🔗](https://leetcode.com/problems/maximum-beauty-of-an-array-after-applying-operation) |
1203+
| 2779 | 数组的最大美丽值 | [[✓]](/problem/2779.md) | [`数组`](/tag/array.md) [`二分查找`](/tag/binary-search.md) [`排序`](/tag/sorting.md) `1+` | 🟠 | [🀄️](https://leetcode.cn/problems/maximum-beauty-of-an-array-after-applying-operation) [🔗](https://leetcode.com/problems/maximum-beauty-of-an-array-after-applying-operation) |
12041204
| 2780 | 合法分割的最小下标 | | [`数组`](/tag/array.md) [`哈希表`](/tag/hash-table.md) [`排序`](/tag/sorting.md) | 🟠 | [🀄️](https://leetcode.cn/problems/minimum-index-of-a-valid-split) [🔗](https://leetcode.com/problems/minimum-index-of-a-valid-split) |
12051205
| 2781 | 最长合法子字符串的长度 | | [`数组`](/tag/array.md) [`哈希表`](/tag/hash-table.md) [`字符串`](/tag/string.md) `1+` | 🔴 | [🀄️](https://leetcode.cn/problems/length-of-the-longest-valid-substring) [🔗](https://leetcode.com/problems/length-of-the-longest-valid-substring) |
12061206

‎problem/0001.md

Copy file name to clipboardExpand all lines: problem/0001.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ var twoSum = function (nums, target) {
9090
| 15 | 三数之和 | [[]](/problem/0015.md) | [`数组`](/tag/array.md) [`双指针`](/tag/two-pointers.md) [`排序`](/tag/sorting.md) | 🟠 | [🀄️](https://leetcode.cn/problems/3sum) [🔗](https://leetcode.com/problems/3sum) |
9191
| 18 | 四数之和 | [[]](/problem/0018.md) | [`数组`](/tag/array.md) [`双指针`](/tag/two-pointers.md) [`排序`](/tag/sorting.md) | 🟠 | [🀄️](https://leetcode.cn/problems/4sum) [🔗](https://leetcode.com/problems/4sum) |
9292
| 167 | 两数之和 II - 输入有序数组 | [[]](/problem/0167.md) | [`数组`](/tag/array.md) [`双指针`](/tag/two-pointers.md) [`二分查找`](/tag/binary-search.md) | 🟠 | [🀄️](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted) [🔗](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted) |
93-
| 170 | 两数之和 III - 数据结构设计 🔒 | | [`设计`](/tag/design.md) [`数组`](/tag/array.md) [`哈希表`](/tag/hash-table.md) `2+` | 🟢 | [🀄️](https://leetcode.cn/problems/two-sum-iii-data-structure-design) [🔗](https://leetcode.com/problems/two-sum-iii-data-structure-design) |
93+
| 170 | 两数之和 III - 数据结构设计 🔒 | [[]](/problem/0170.md) | [`设计`](/tag/design.md) [`数组`](/tag/array.md) [`哈希表`](/tag/hash-table.md) `2+` | 🟢 | [🀄️](https://leetcode.cn/problems/two-sum-iii-data-structure-design) [🔗](https://leetcode.com/problems/two-sum-iii-data-structure-design) |
9494
| 560 | 和为 K 的子数组 | [[]](/problem/0560.md) | [`数组`](/tag/array.md) [`哈希表`](/tag/hash-table.md) [`前缀和`](/tag/prefix-sum.md) | 🟠 | [🀄️](https://leetcode.cn/problems/subarray-sum-equals-k) [🔗](https://leetcode.com/problems/subarray-sum-equals-k) |
9595
| 653 | 两数之和 IV - 输入二叉搜索树 | | [``](/tag/tree.md) [`深度优先搜索`](/tag/depth-first-search.md) [`广度优先搜索`](/tag/breadth-first-search.md) `4+` | 🟢 | [🀄️](https://leetcode.cn/problems/two-sum-iv-input-is-a-bst) [🔗](https://leetcode.com/problems/two-sum-iv-input-is-a-bst) |
9696
| 1099 | 小于 K 的两数之和 🔒 | | [`数组`](/tag/array.md) [`双指针`](/tag/two-pointers.md) [`二分查找`](/tag/binary-search.md) `1+` | 🟢 | [🀄️](https://leetcode.cn/problems/two-sum-less-than-k) [🔗](https://leetcode.com/problems/two-sum-less-than-k) |

‎problem/0031.md

Copy file name to clipboardExpand all lines: problem/0031.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,6 @@ var nextPermutation = function (nums) {
148148
| :------: | :------ | :------: | :------ | :------: | :------: |
149149
| 46 | 全排列 | [[]](/problem/0046.md) | [`数组`](/tag/array.md) [`回溯`](/tag/backtracking.md) | 🟠 | [🀄️](https://leetcode.cn/problems/permutations) [🔗](https://leetcode.com/problems/permutations) |
150150
| 47 | 全排列 II | [[]](/problem/0047.md) | [`数组`](/tag/array.md) [`回溯`](/tag/backtracking.md) | 🟠 | [🀄️](https://leetcode.cn/problems/permutations-ii) [🔗](https://leetcode.com/problems/permutations-ii) |
151-
| 60 | 排列序列 | | [`递归`](/tag/recursion.md) [`数学`](/tag/math.md) | 🔴 | [🀄️](https://leetcode.cn/problems/permutation-sequence) [🔗](https://leetcode.com/problems/permutation-sequence) |
151+
| 60 | 排列序列 | [[]](/problem/0060.md) | [`递归`](/tag/recursion.md) [`数学`](/tag/math.md) | 🔴 | [🀄️](https://leetcode.cn/problems/permutation-sequence) [🔗](https://leetcode.com/problems/permutation-sequence) |
152152
| 267 | 回文排列 II 🔒 | | [`哈希表`](/tag/hash-table.md) [`字符串`](/tag/string.md) [`回溯`](/tag/backtracking.md) | 🟠 | [🀄️](https://leetcode.cn/problems/palindrome-permutation-ii) [🔗](https://leetcode.com/problems/palindrome-permutation-ii) |
153153
| 1850 | 邻位交换的最小次数 | | [`贪心`](/tag/greedy.md) [`双指针`](/tag/two-pointers.md) [`字符串`](/tag/string.md) | 🟠 | [🀄️](https://leetcode.cn/problems/minimum-adjacent-swaps-to-reach-the-kth-smallest-number) [🔗](https://leetcode.com/problems/minimum-adjacent-swaps-to-reach-the-kth-smallest-number) |

‎problem/0046.md

Copy file name to clipboardExpand all lines: problem/0046.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,5 @@ var permute = function (nums) {
117117
| :------: | :------ | :------: | :------ | :------: | :------: |
118118
| 31 | 下一个排列 | [[]](/problem/0031.md) | [`数组`](/tag/array.md) [`双指针`](/tag/two-pointers.md) | 🟠 | [🀄️](https://leetcode.cn/problems/next-permutation) [🔗](https://leetcode.com/problems/next-permutation) |
119119
| 47 | 全排列 II | [[]](/problem/0047.md) | [`数组`](/tag/array.md) [`回溯`](/tag/backtracking.md) | 🟠 | [🀄️](https://leetcode.cn/problems/permutations-ii) [🔗](https://leetcode.com/problems/permutations-ii) |
120-
| 60 | 排列序列 | | [`递归`](/tag/recursion.md) [`数学`](/tag/math.md) | 🔴 | [🀄️](https://leetcode.cn/problems/permutation-sequence) [🔗](https://leetcode.com/problems/permutation-sequence) |
120+
| 60 | 排列序列 | [[]](/problem/0060.md) | [`递归`](/tag/recursion.md) [`数学`](/tag/math.md) | 🔴 | [🀄️](https://leetcode.cn/problems/permutation-sequence) [🔗](https://leetcode.com/problems/permutation-sequence) |
121121
| 77 | 组合 | [[]](/problem/0077.md) | [`回溯`](/tag/backtracking.md) | 🟠 | [🀄️](https://leetcode.cn/problems/combinations) [🔗](https://leetcode.com/problems/combinations) |

‎problem/0060.md

Copy file name to clipboard
+182Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
---
2+
title: 60. 排列序列
3+
description: LeetCode 60. 排列序列题解,Permutation Sequence,包含解题思路、复杂度分析以及完整的 JavaScript 代码实现。
4+
keywords:
5+
- LeetCode
6+
- 60. 排列序列
7+
- 排列序列
8+
- Permutation Sequence
9+
- 解题思路
10+
- 递归
11+
- 数学
12+
---
13+
14+
# 60. 排列序列
15+
16+
🔴 <font color=#ff334b>Hard</font>&emsp; 🔖&ensp; [`递归`](/tag/recursion.md) [`数学`](/tag/math.md)&emsp; 🔗&ensp;[`力扣`](https://leetcode.cn/problems/permutation-sequence) [`LeetCode`](https://leetcode.com/problems/permutation-sequence)
17+
18+
## 题目
19+
20+
The set `[1, 2, 3, ..., n]` contains a total of `n!` unique permutations.
21+
22+
By listing and labeling all of the permutations in order, we get the following
23+
sequence for `n = 3`:
24+
25+
1. `"123"`
26+
2. `"132"`
27+
3. `"213"`
28+
4. `"231"`
29+
5. `"312"`
30+
6. `"321"`
31+
32+
Given `n` and `k`, return the `kth` permutation sequence.
33+
34+
**Example 1:**
35+
36+
> Input: n = 3, k = 3
37+
>
38+
> Output: "213"
39+
40+
**Example 2:**
41+
42+
> Input: n = 4, k = 9
43+
>
44+
> Output: "2314"
45+
46+
**Example 3:**
47+
48+
> Input: n = 3, k = 1
49+
>
50+
> Output: "123"
51+
52+
**Constraints:**
53+
54+
- `1 <= n <= 9`
55+
- `1 <= k <= n!`
56+
57+
## 题目大意
58+
59+
给出集合 `[1,2,3,...,n]`,其所有元素共有 `n!` 种排列。
60+
61+
按大小顺序列出所有排列情况,并一一标记,当 `n = 3` 时, 所有排列如下:
62+
63+
1. `"123"`
64+
2. `"132"`
65+
3. `"213"`
66+
4. `"231"`
67+
5. `"312"`
68+
6. `"321"`
69+
70+
给定 `n``k`,返回第 `k` 个排列。
71+
72+
**示例 1:**
73+
74+
> **输入:** n = 3, k = 3
75+
>
76+
> **输出:** "213"
77+
78+
**示例 2:**
79+
80+
> **输入:** n = 4, k = 9
81+
>
82+
> **输出:** "2314"
83+
84+
**示例 3:**
85+
86+
> **输入:** n = 3, k = 1
87+
>
88+
> **输出:** "123"
89+
90+
**提示:**
91+
92+
- `1 <= n <= 9`
93+
- `1 <= k <= n!`
94+
95+
## 解题思路
96+
97+
这道题的核心是利用数学方法直接定位到第 `k` 个排列,而不是逐个生成所有排列。
98+
99+
1. **阶乘性质**
100+
101+
对于长度为 `n` 的排列:
102+
103+
- 每个数字可以作为排列的第一个数字。
104+
- 当第一个数字固定后,其余数字的排列共有 `(n-1)!` 种可能。
105+
106+
例如:
107+
108+
- 对于 `n = 3` 的排列 `["123", "132", "213", "231", "312", "321"]`
109+
- 第一个数字为 `1` 的排列有 `2! = 2` 个:`["123", "132"]`
110+
- 第一个数字为 `2` 的排列有 `2! = 2` 个:`["213", "231"]`
111+
- 第一个数字为 `3` 的排列有 `2! = 2` 个:`["312", "321"]`
112+
113+
2. **如何确定第一个数字**
114+
115+
- 使用 `k``(n-1)!` 的关系确定第一个数字。
116+
- 计算 `index = Math.floor((k-1) / (n-1)!)`,这个 `index` 表示当前可用数字中哪个数字是第一个。
117+
- 更新 `k = k % (n-1)!`,继续对剩余的排列进行同样的计算。
118+
119+
3. **重复以上过程**
120+
121+
- 每次固定一个数字,直到所有数字固定为止。
122+
123+
---
124+
125+
**算法步骤**
126+
127+
1. **预计算阶乘**
128+
- 构造一个数组 `factorial`,保存 `0!``(n-1)!` 的值。
129+
2. **维护候选数字**
130+
- 使用一个数组 `nums` 保存当前可用的数字(初始为 `[1, 2, ..., n]`)。
131+
3. **逐位确定数字**
132+
- 对于第 `i` 位,计算 `index` 和更新 `k`
133+
- 根据 `index``nums` 中取出数字,加入结果。
134+
135+
#### 复杂度分析
136+
137+
- **时间复杂度**`O(n^2)`
138+
139+
- 计算阶乘:`O(n)`
140+
- 每次选取数字要进行数组的 `splice` 操作,复杂度为`O(n)`,最多取 `n` 次,总复杂度:`O(n^2)`
141+
142+
- **空间复杂度**`O(n)`,存储阶乘和候选数字。
143+
144+
## 代码
145+
146+
```javascript
147+
/**
148+
* @param {number} n
149+
* @param {number} k
150+
* @return {string}
151+
*/
152+
var getPermutation = function (n, k) {
153+
// 计算阶乘
154+
const factorial = Array(n).fill(1);
155+
for (let i = 1; i < n; i++) {
156+
factorial[i] = factorial[i - 1] * i;
157+
}
158+
159+
// 初始化候选数字
160+
const nums = Array.from({ length: n }, (_, i) => i + 1);
161+
let result = '';
162+
163+
// 从最高位到最低位确定数字
164+
k--; // 转为从 0 开始的索引
165+
for (let i = n; i > 0; i--) {
166+
const index = Math.floor(k / factorial[i - 1]);
167+
result += nums[index];
168+
nums.splice(index, 1); // 移除已选数字
169+
k %= factorial[i - 1]; // 更新 k
170+
}
171+
172+
return result;
173+
};
174+
```
175+
176+
## 相关题目
177+
178+
<!-- prettier-ignore -->
179+
| 题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
180+
| :------: | :------ | :------: | :------ | :------: | :------: |
181+
| 31 | 下一个排列 | [[]](/problem/0031.md) | [`数组`](/tag/array.md) [`双指针`](/tag/two-pointers.md) | 🟠 | [🀄️](https://leetcode.cn/problems/next-permutation) [🔗](https://leetcode.com/problems/next-permutation) |
182+
| 46 | 全排列 | [[]](/problem/0046.md) | [`数组`](/tag/array.md) [`回溯`](/tag/backtracking.md) | 🟠 | [🀄️](https://leetcode.cn/problems/permutations) [🔗](https://leetcode.com/problems/permutations) |

‎problem/0081.md

Copy file name to clipboardExpand all lines: problem/0081.md
+55-23Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ You must decrease the overall operation steps as much as possible.
5050
- `nums` is guaranteed to be rotated at some pivot.
5151
- `-10^4 <= target <= 10^4`
5252

53-
**Follow up:** This problem is similar to [Search in Rotated Sorted
54-
Array](/problems/search-in-rotated-sorted-array/description/), but `nums` may
55-
contain **duplicates**. Would this affect the runtime complexity? How and why?
53+
**Follow up:** This problem is similar to [Search in Rotated SortedArray](./0033.md), but `nums` may contain **duplicates**. Would this affect the runtime complexity? How and why?
5654

5755
## 题目大意
5856

@@ -64,17 +62,35 @@ contain **duplicates**. Would this affect the runtime complexity? How and why?
6462

6563
你必须尽可能减少整个操作步骤。
6664

65+
**进阶:**
66+
67+
此题与 [搜索旋转排序数组](./0033.md) 相似,但本题中的 `nums` 可能包含 **重复** 元素。这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
68+
6769
## 解题思路
6870

69-
可以使用修改版的二分查找算法来解决这个问题。
71+
这道题与[第 33 题 搜索旋转排序数组](./0033.md) 相似,区别是本题中的 `nums` 可能包含 **重复** 元素,因此需要增加**第 3 步**,跳过潜在的重复性。
72+
73+
由于数组是部分有序的,可以利用 **二分查找** 的思想来解决这个问题。与普通的二分查找不同,这里数组被旋转过,所以需要通过额外的判断来确定二分查找的方向。
74+
75+
1. 首先,数组依然可以通过中间值 `mid` 将左右部分分为有序和无序两部分。
76+
2. 每次找到中间位置 `mid`,先检查 `nums[mid]` 是否等于目标值。如果相等,直接返回索引。
77+
3. 接着检查 `nums[left]``nums[mid]` 值是否相同,如果相同,则需要处理重复项,在这种情况下,可以增加 `left` 以跳过潜在的重复项。
78+
4. 通过 `nums[left]``nums[mid]` 的大小关系来判断哪一部分是有序的。
7079

71-
可以定义两个指针 `left``right`,分别指向数组的起始和结束位置。在每一步查找中,计算中间位置 `mid`。如果 `nums[mid]` 等于目标值,那么直接返回 `true`
80+
- 通过比较 `nums[left]``nums[mid]` 可以判断左半部分是否有序。
81+
- 如果 `nums[left] <= nums[mid]`,说明左半部分是有序的,否则右半部分有序。
7282

73-
然后,需要处理数组被旋转的情况。在正常的有序数组中,左半部分的元素总是小于等于右半部分的元素。如果 `nums[left] <= nums[mid]`,说明左半部分是有序的。在这种情况下,可以判断目标值是否在左半部分,如果是,则将 `right` 指针移到 `mid - 1` 处;否则,将 `left` 指针移到 `mid + 1` 处。
83+
5. 判断目标值的位置:
7484

75-
反之,如果 `nums[left] > nums[mid]`,说明右半部分是有序的。在这种情况下,可以判断目标值是否在右半部分,如果是,则将 `left` 指针移到 `mid + 1` 处;否则,将 `right` 指针移到 `mid - 1` 处。
85+
- 如果左半部分有序,且目标值落在 `nums[left]``nums[mid]` 之间,那么缩小搜索范围至左半部分,否则去右半部分继续查找。
86+
- 如果右半部分有序,且目标值落在 `nums[mid]``nums[right]` 之间,那么缩小搜索范围至右半部分,否则去左半部分继续查找。
7687

77-
通过不断缩小搜索范围,最终可以找到目标值或者确定不存在。
88+
6. 不断缩小查找区间,直到找到目标值,或者使得 `left > right`时返回 `-1`
89+
90+
#### 复杂度分析
91+
92+
- **时间复杂度**`O(log n)`,这是二分查找的时间复杂度,每次查找时将搜索范围缩小一半。
93+
- **空间复杂度**`O(1)`,只用了常量级的额外空间。
7894

7995
## 代码
8096

@@ -87,27 +103,43 @@ contain **duplicates**. Would this affect the runtime complexity? How and why?
87103
var search = function (nums, target) {
88104
let left = 0;
89105
let right = nums.length - 1;
106+
90107
while (left <= right) {
91-
const mid = Math.floor((right - left) / 2) + left;
108+
let mid = Math.floor((left + right) / 2);
109+
110+
// 找到目标值
111+
if (nums[mid] === target) {
112+
return mid;
113+
}
114+
115+
// 跳过潜在的重复项
116+
if (nums[left] == nums[mid]) {
117+
left++;
118+
continue;
119+
}
120+
121+
// 判断左半部分是否有序
92122
if (nums[left] <= nums[mid]) {
93-
if (nums[mid] > target) {
94-
right = mid - 1;
95-
} else if (nums[mid] < target) {
96-
left = mid + 1;
97-
} else if (nums[mid] == target) {
98-
return true;
123+
// 如果 target 在左半部分的范围内
124+
if (nums[left] <= target && target < nums[mid]) {
125+
right = mid - 1; // 缩小到左半部分
126+
} else {
127+
left = mid + 1; // 否则缩小到右半部分
99128
}
100-
} else {
101-
if (nums[mid] > target) {
102-
right = mid - 1;
103-
} else if (nums[mid] < target) {
104-
left = mid + 1;
105-
} else if (nums[mid] == target) {
106-
return true;
129+
}
130+
// 否则右半部分有序
131+
else {
132+
// 如果 target 在右半部分的范围内
133+
if (nums[mid] < target && target <= nums[right]) {
134+
left = mid + 1; // 缩小到右半部分
135+
} else {
136+
right = mid - 1; // 否则缩小到左半部分
107137
}
108138
}
109139
}
110-
return false;
140+
141+
// 没有找到目标值
142+
return -1;
111143
};
112144
```
113145

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.